[RFC,3/5] RISC-V: Save and restore VCSR when doing user context switch

Message ID 1631497278-29829-4-git-send-email-vincent.chen@sifive.com
State RFC, archived
Headers
Series RISC-V: Add vector ISA support |

Checks

Context Check Description
dj/TryBot-apply_patch success Patch applied to master at the time it was sent

Commit Message

Vincent Chen Sept. 13, 2021, 1:41 a.m. UTC
  According to the RISC-V V extension specification, all vector registers
except VCSR are caller-saved registers. The VCSR (vxrm + vxsat) has thread
storage duration. Therefore, only VCSR needs to be added to the user
context operation.
---
 sysdeps/riscv/Makefile                       |  5 ++++
 sysdeps/riscv/rtld-global-offsets.sym        |  7 +++++
 sysdeps/unix/sysv/linux/riscv/bits/hwcap.h   | 31 +++++++++++++++++++++
 sysdeps/unix/sysv/linux/riscv/getcontext.S   | 22 ++++++++++++++-
 sysdeps/unix/sysv/linux/riscv/setcontext.S   | 22 +++++++++++++++
 sysdeps/unix/sysv/linux/riscv/swapcontext.S  | 41 ++++++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/riscv/sysdep.h       |  1 +
 sysdeps/unix/sysv/linux/riscv/ucontext_i.sym |  6 ++++
 8 files changed, 134 insertions(+), 1 deletion(-)
 create mode 100644 sysdeps/riscv/rtld-global-offsets.sym
 create mode 100644 sysdeps/unix/sysv/linux/riscv/bits/hwcap.h
  

Comments

Joseph Myers Sept. 14, 2021, 11:48 p.m. UTC | #1
On Mon, 13 Sep 2021, Vincent Chen wrote:

> According to the RISC-V V extension specification, all vector registers
> except VCSR are caller-saved registers. The VCSR (vxrm + vxsat) has thread
> storage duration. Therefore, only VCSR needs to be added to the user
> context operation.

What is the intended programming model for using vxrm and vxsat?

The expectation for the floating-point rounding modes and flags is that 
they work just like user-defined _Thread_local variables - that is, they 
are *not* saved or restored by setjmp/longjmp or *context functions.  It 
would be natural to expect fixed-point rounding modes and flags to work 
similarly.
  
Andrew Waterman Sept. 15, 2021, 12:13 a.m. UTC | #2
On Tue, Sep 14, 2021 at 4:48 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Mon, 13 Sep 2021, Vincent Chen wrote:
>
> > According to the RISC-V V extension specification, all vector registers
> > except VCSR are caller-saved registers. The VCSR (vxrm + vxsat) has thread
> > storage duration. Therefore, only VCSR needs to be added to the user
> > context operation.
>
> What is the intended programming model for using vxrm and vxsat?
>
> The expectation for the floating-point rounding modes and flags is that
> they work just like user-defined _Thread_local variables - that is, they
> are *not* saved or restored by setjmp/longjmp or *context functions.  It
> would be natural to expect fixed-point rounding modes and flags to work
> similarly.

Indeed, Joseph, vxsat and vxrm should be treated analogously to the FP
flags and rounding mode, respectively.

>
> --
> Joseph S. Myers
> joseph@codesourcery.com
  
Vincent Chen Sept. 16, 2021, 9:20 a.m. UTC | #3
On Wed, Sep 15, 2021 at 8:13 AM Andrew Waterman <andrew@sifive.com> wrote:
>
> On Tue, Sep 14, 2021 at 4:48 PM Joseph Myers <joseph@codesourcery.com> wrote:
> >
> > On Mon, 13 Sep 2021, Vincent Chen wrote:
> >
> > > According to the RISC-V V extension specification, all vector registers
> > > except VCSR are caller-saved registers. The VCSR (vxrm + vxsat) has thread
> > > storage duration. Therefore, only VCSR needs to be added to the user
> > > context operation.
> >
> > What is the intended programming model for using vxrm and vxsat?
> >
> > The expectation for the floating-point rounding modes and flags is that
> > they work just like user-defined _Thread_local variables - that is, they
> > are *not* saved or restored by setjmp/longjmp or *context functions.  It
> > would be natural to expect fixed-point rounding modes and flags to work
> > similarly.
>
> Indeed, Joseph, vxsat and vxrm should be treated analogously to the FP
> flags and rounding mode, respectively.
>

OK, I understood. As Andrew mentioned, the vxsat and vxrm should be
treated analogously to the FP flags and rounding mode. Therefore, the
VCSR should not be saved and restored in *context functions. I think
this patch can be dropped in the next version patch. Thank Joseph and
Andrew for the kind reply.

Thanks,
Vincent
> >
> > --
> > Joseph S. Myers
> > joseph@codesourcery.com
  
Adhemerval Zanella Oct. 1, 2021, 1:04 p.m. UTC | #4
On 12/09/2021 22:41, Vincent Chen wrote:
> According to the RISC-V V extension specification, all vector registers
> except VCSR are caller-saved registers. The VCSR (vxrm + vxsat) has thread
> storage duration. Therefore, only VCSR needs to be added to the user
> context operation.
> ---
>  sysdeps/riscv/Makefile                       |  5 ++++
>  sysdeps/riscv/rtld-global-offsets.sym        |  7 +++++
>  sysdeps/unix/sysv/linux/riscv/bits/hwcap.h   | 31 +++++++++++++++++++++
>  sysdeps/unix/sysv/linux/riscv/getcontext.S   | 22 ++++++++++++++-
>  sysdeps/unix/sysv/linux/riscv/setcontext.S   | 22 +++++++++++++++
>  sysdeps/unix/sysv/linux/riscv/swapcontext.S  | 41 ++++++++++++++++++++++++++++
>  sysdeps/unix/sysv/linux/riscv/sysdep.h       |  1 +
>  sysdeps/unix/sysv/linux/riscv/ucontext_i.sym |  6 ++++
>  8 files changed, 134 insertions(+), 1 deletion(-)
>  create mode 100644 sysdeps/riscv/rtld-global-offsets.sym
>  create mode 100644 sysdeps/unix/sysv/linux/riscv/bits/hwcap.h
> 
> diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile
> index 20a9968..cda3ded 100644
> --- a/sysdeps/riscv/Makefile
> +++ b/sysdeps/riscv/Makefile
> @@ -2,6 +2,11 @@ ifeq ($(subdir),misc)
>  sysdep_headers += sys/asm.h
>  endif
>  
> +ifeq ($(subdir),csu)
> +# get offset to rtld_global._dl_hwcap and rtld_global._dl_hwcap2.
> +gen-as-const-headers += rtld-global-offsets.sym
> +endif
> +
>  # RISC-V's assembler also needs to know about PIC as it changes the definition
>  # of some assembler macros.
>  ASFLAGS-.os += $(pic-ccflag)
> diff --git a/sysdeps/riscv/rtld-global-offsets.sym b/sysdeps/riscv/rtld-global-offsets.sym
> new file mode 100644
> index 0000000..ff4e97f
> --- /dev/null
> +++ b/sysdeps/riscv/rtld-global-offsets.sym
> @@ -0,0 +1,7 @@
> +#define SHARED 1
> +
> +#include <ldsodefs.h>
> +
> +#define rtld_global_ro_offsetof(mem) offsetof (struct rtld_global_ro, mem)
> +
> +RTLD_GLOBAL_RO_DL_HWCAP_OFFSET	rtld_global_ro_offsetof (_dl_hwcap)
> diff --git a/sysdeps/unix/sysv/linux/riscv/bits/hwcap.h b/sysdeps/unix/sysv/linux/riscv/bits/hwcap.h
> new file mode 100644
> index 0000000..e6c5ef5
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/riscv/bits/hwcap.h
> @@ -0,0 +1,31 @@
> +/* Defines for bits in AT_HWCAP.  RISC-V Linux version.
> +   Copyright (C) 2021 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/>.  */
> +
> +#if !defined (_SYS_AUXV_H) && !defined (_LINUX_RISCV_SYSDEP_H)

_LINUX_RISCV_SYSDEP_H is defined by an internal header only, so I
think it should no be referenced by an exported one.

> +# error "Never include <bits/hwcap.h> directly; use <sys/auxv.h> instead."
> +#endif
> +
> +/* The following must match the kernel's <asm/hwcap.h>.  */
> +#define HWCAP_ISA_I      0x100		//(1 << ('I' - 'A'))
> +#define HWCAP_ISA_M      0x1000 	//(1 << ('M' - 'A'))
> +#define HWCAP_ISA_A      0x1		//(1 << ('A' - 'A'))
> +#define HWCAP_ISA_F      0x20		//(1 << ('F' - 'A'))
> +#define HWCAP_ISA_D      0x8		//(1 << ('D' - 'A'))
> +#define HWCAP_ISA_C      0x4		//(1 << ('C' - 'A'))
> +#define HWCAP_ISA_V      0x200000	//(1 << ('V' - 'A'))
> +
> diff --git a/sysdeps/unix/sysv/linux/riscv/getcontext.S b/sysdeps/unix/sysv/linux/riscv/getcontext.S
> index d6a9bbc..840d8fe 100644
> --- a/sysdeps/unix/sysv/linux/riscv/getcontext.S
> +++ b/sysdeps/unix/sysv/linux/riscv/getcontext.S
> @@ -16,6 +16,8 @@
>     License along with the GNU C Library.  If not, see
>     <https://www.gnu.org/licenses/>.  */
>  
> +#include <sysdep.h>
> +#include <rtld-global-offsets.h>
>  #include "ucontext-macros.h"
>  
>  /* int getcontext (ucontext_t *ucp) */
> @@ -39,6 +41,25 @@ LEAF (__getcontext)
>  	SAVE_INT_REG (s10, 26, a0)
>  	SAVE_INT_REG (s11, 27, a0)
>  
> +#ifdef __riscv_vector

I take '__riscv_vector' would be defined by the compiler (although there is
no gcc support yet).  Why do you need to build iff vector extension is being
use if you are checking the hwcap?

For __riscv_float_abi_soft it does make sense since 'frsr' will be issue
regardless.

> +# ifdef SHARED
> +	la	t1, _rtld_global_ro
> +	REG_L   t1, RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(t1)
> +# else
> +	la	t1, _dl_hwcap
> +	REG_L	t1, (t1)
> +# endif
> +	li	t2, HWCAP_ISA_V
> +	and	t2, t1, t2
> +	beqz	t2, 1f
> +	addi	t2, a0,	MCONTEXT_EXTENSION
> +	li	t1, RVV_MAGIC
> +	sw	t1, (t2)
> +	csrr	t1, vcsr
> +	REG_S	t1, VCSR_OFFSET(t2)
> +1:
> +#endif
> +
>  #ifndef __riscv_float_abi_soft
>  	frsr	a1
>  
> @@ -73,5 +94,4 @@ LEAF (__getcontext)
>  99:	j	__syscall_error
>  
>  PSEUDO_END (__getcontext)
> -
>  weak_alias (__getcontext, getcontext)
> diff --git a/sysdeps/unix/sysv/linux/riscv/setcontext.S b/sysdeps/unix/sysv/linux/riscv/setcontext.S
> index 9510518..d2404fb 100644
> --- a/sysdeps/unix/sysv/linux/riscv/setcontext.S
> +++ b/sysdeps/unix/sysv/linux/riscv/setcontext.S
> @@ -16,6 +16,8 @@
>     License along with the GNU C Library.  If not, see
>     <https://www.gnu.org/licenses/>.  */
>  
> +#include <sysdep.h>
> +#include <rtld-global-offsets.h>
>  #include "ucontext-macros.h"
>  
>  /*  int __setcontext (const ucontext_t *ucp)
> @@ -64,6 +66,26 @@ LEAF (__setcontext)
>  	fssr	t1
>  #endif /* __riscv_float_abi_soft */
>  
> +#ifdef __riscv_vector
> +#ifdef SHARED
> +	la	t1, _rtld_global_ro
> +	REG_L   t1, RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(t1)
> +#else
> +	la	t1, _dl_hwcap
> +	REG_L	t1, (t1)
> +#endif
> +	li	t2, HWCAP_ISA_V
> +	and	t2, t1, t2
> +	beqz	t2, 1f
> +	li      t1, RVV_MAGIC
> +	addi	t2, t0,	MCONTEXT_EXTENSION
> +	lw	a1, (t2)
> +	bne	a1, t1, 1f
> +	REG_L   t1, VCSR_OFFSET(t2)
> +	csrw	vcsr, t1
> +1:
> +#endif
> +
>  	/* Note the contents of argument registers will be random
>  	   unless makecontext() has been called.  */
>  	RESTORE_INT_REG     (t1,   0, t0)
> diff --git a/sysdeps/unix/sysv/linux/riscv/swapcontext.S b/sysdeps/unix/sysv/linux/riscv/swapcontext.S
> index df0f699..94ae8e4 100644
> --- a/sysdeps/unix/sysv/linux/riscv/swapcontext.S
> +++ b/sysdeps/unix/sysv/linux/riscv/swapcontext.S
> @@ -16,6 +16,8 @@
>     License along with the GNU C Library.  If not, see
>     <https://www.gnu.org/licenses/>.  */
>  
> +#include <sysdep.h>
> +#include <rtld-global-offsets.h>
>  #include "ucontext-macros.h"
>  
>  /* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
> @@ -40,6 +42,25 @@ LEAF (__swapcontext)
>  	SAVE_INT_REG (s10, 26, a0)
>  	SAVE_INT_REG (s11, 27, a0)
>  
> +#ifdef __riscv_vector
> +#ifdef SHARED
> +	la      t1, _rtld_global_ro
> +	REG_L   t1, RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(t1)
> +#else
> +	la	t1, _dl_hwcap
> +	REG_L   t1, (t1)
> +#endif
> +	li	t2, HWCAP_ISA_V
> +	and	t2, t1, t2
> +	beqz	t2, 1f
> +	addi	t2, a0,	MCONTEXT_EXTENSION
> +	li	t1, RVV_MAGIC
> +	sw	t1, (t2)
> +	csrr	t1, vcsr
> +	REG_S	t1, VCSR_OFFSET(t2)
> +1:
> +#endif
> +
>  #ifndef __riscv_float_abi_soft
>  	frsr a1
>  
> @@ -89,6 +110,26 @@ LEAF (__swapcontext)
>  	fssr	t1
>  #endif /* __riscv_float_abi_soft */
>  
> +#ifdef __riscv_vector
> +#ifdef SHARED
> +	la      t1, _rtld_global_ro
> +	REG_L   t1, RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(t1)
> +#else
> +	la	t1, _dl_hwcap
> +	REG_L   t1, (t1)
> +#endif
> +	li	t2, HWCAP_ISA_V
> +	and	t2, t1, t2
> +	beqz	t2, 1f
> +	li      t1, RVV_MAGIC
> +	addi	t2, t0,	MCONTEXT_EXTENSION
> +	lw	a1, (t2)
> +	bne	a1, t1, 1f
> +	REG_L   t1, VCSR_OFFSET(t2)
> +	csrw	vcsr, t1
> +1:
> +#endif
> +
>  	/* Note the contents of argument registers will be random
>  	   unless makecontext() has been called.  */
>  	RESTORE_INT_REG (t1,   0, t0)
> diff --git a/sysdeps/unix/sysv/linux/riscv/sysdep.h b/sysdeps/unix/sysv/linux/riscv/sysdep.h
> index 37ff07a..c9f8fd8 100644
> --- a/sysdeps/unix/sysv/linux/riscv/sysdep.h
> +++ b/sysdeps/unix/sysv/linux/riscv/sysdep.h
> @@ -50,6 +50,7 @@
>  
>  #ifdef __ASSEMBLER__
>  
> +# include <bits/hwcap.h>
>  # include <sys/asm.h>
>  
>  # define ENTRY(name) LEAF(name)
> diff --git a/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym b/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym
> index be55b26..4037473 100644
> --- a/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym
> +++ b/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym
> @@ -2,6 +2,7 @@
>  #include <signal.h>
>  #include <stddef.h>
>  #include <sys/ucontext.h>
> +#include <asm/sigcontext.h>
>  
>  -- Constants used by the rt_sigprocmask call.
>  
> @@ -27,5 +28,10 @@ STACK_FLAGS			stack (ss_flags)
>  
>  MCONTEXT_GREGS			mcontext (__gregs)
>  MCONTEXT_FPREGS			mcontext (__fpregs)
> +MCONTEXT_EXTENSION 		mcontext (__reserved)
>  
>  UCONTEXT_SIZE			sizeof (ucontext_t)
> +
> +VCSR_OFFSET			offsetof (struct __riscv_v_state, vcsr)
> +
> +RVV_MAGIC
>
  

Patch

diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile
index 20a9968..cda3ded 100644
--- a/sysdeps/riscv/Makefile
+++ b/sysdeps/riscv/Makefile
@@ -2,6 +2,11 @@  ifeq ($(subdir),misc)
 sysdep_headers += sys/asm.h
 endif
 
+ifeq ($(subdir),csu)
+# get offset to rtld_global._dl_hwcap and rtld_global._dl_hwcap2.
+gen-as-const-headers += rtld-global-offsets.sym
+endif
+
 # RISC-V's assembler also needs to know about PIC as it changes the definition
 # of some assembler macros.
 ASFLAGS-.os += $(pic-ccflag)
diff --git a/sysdeps/riscv/rtld-global-offsets.sym b/sysdeps/riscv/rtld-global-offsets.sym
new file mode 100644
index 0000000..ff4e97f
--- /dev/null
+++ b/sysdeps/riscv/rtld-global-offsets.sym
@@ -0,0 +1,7 @@ 
+#define SHARED 1
+
+#include <ldsodefs.h>
+
+#define rtld_global_ro_offsetof(mem) offsetof (struct rtld_global_ro, mem)
+
+RTLD_GLOBAL_RO_DL_HWCAP_OFFSET	rtld_global_ro_offsetof (_dl_hwcap)
diff --git a/sysdeps/unix/sysv/linux/riscv/bits/hwcap.h b/sysdeps/unix/sysv/linux/riscv/bits/hwcap.h
new file mode 100644
index 0000000..e6c5ef5
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/riscv/bits/hwcap.h
@@ -0,0 +1,31 @@ 
+/* Defines for bits in AT_HWCAP.  RISC-V Linux version.
+   Copyright (C) 2021 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/>.  */
+
+#if !defined (_SYS_AUXV_H) && !defined (_LINUX_RISCV_SYSDEP_H)
+# error "Never include <bits/hwcap.h> directly; use <sys/auxv.h> instead."
+#endif
+
+/* The following must match the kernel's <asm/hwcap.h>.  */
+#define HWCAP_ISA_I      0x100		//(1 << ('I' - 'A'))
+#define HWCAP_ISA_M      0x1000 	//(1 << ('M' - 'A'))
+#define HWCAP_ISA_A      0x1		//(1 << ('A' - 'A'))
+#define HWCAP_ISA_F      0x20		//(1 << ('F' - 'A'))
+#define HWCAP_ISA_D      0x8		//(1 << ('D' - 'A'))
+#define HWCAP_ISA_C      0x4		//(1 << ('C' - 'A'))
+#define HWCAP_ISA_V      0x200000	//(1 << ('V' - 'A'))
+
diff --git a/sysdeps/unix/sysv/linux/riscv/getcontext.S b/sysdeps/unix/sysv/linux/riscv/getcontext.S
index d6a9bbc..840d8fe 100644
--- a/sysdeps/unix/sysv/linux/riscv/getcontext.S
+++ b/sysdeps/unix/sysv/linux/riscv/getcontext.S
@@ -16,6 +16,8 @@ 
    License along with the GNU C Library.  If not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+#include <rtld-global-offsets.h>
 #include "ucontext-macros.h"
 
 /* int getcontext (ucontext_t *ucp) */
@@ -39,6 +41,25 @@  LEAF (__getcontext)
 	SAVE_INT_REG (s10, 26, a0)
 	SAVE_INT_REG (s11, 27, a0)
 
+#ifdef __riscv_vector
+# ifdef SHARED
+	la	t1, _rtld_global_ro
+	REG_L   t1, RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(t1)
+# else
+	la	t1, _dl_hwcap
+	REG_L	t1, (t1)
+# endif
+	li	t2, HWCAP_ISA_V
+	and	t2, t1, t2
+	beqz	t2, 1f
+	addi	t2, a0,	MCONTEXT_EXTENSION
+	li	t1, RVV_MAGIC
+	sw	t1, (t2)
+	csrr	t1, vcsr
+	REG_S	t1, VCSR_OFFSET(t2)
+1:
+#endif
+
 #ifndef __riscv_float_abi_soft
 	frsr	a1
 
@@ -73,5 +94,4 @@  LEAF (__getcontext)
 99:	j	__syscall_error
 
 PSEUDO_END (__getcontext)
-
 weak_alias (__getcontext, getcontext)
diff --git a/sysdeps/unix/sysv/linux/riscv/setcontext.S b/sysdeps/unix/sysv/linux/riscv/setcontext.S
index 9510518..d2404fb 100644
--- a/sysdeps/unix/sysv/linux/riscv/setcontext.S
+++ b/sysdeps/unix/sysv/linux/riscv/setcontext.S
@@ -16,6 +16,8 @@ 
    License along with the GNU C Library.  If not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+#include <rtld-global-offsets.h>
 #include "ucontext-macros.h"
 
 /*  int __setcontext (const ucontext_t *ucp)
@@ -64,6 +66,26 @@  LEAF (__setcontext)
 	fssr	t1
 #endif /* __riscv_float_abi_soft */
 
+#ifdef __riscv_vector
+#ifdef SHARED
+	la	t1, _rtld_global_ro
+	REG_L   t1, RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(t1)
+#else
+	la	t1, _dl_hwcap
+	REG_L	t1, (t1)
+#endif
+	li	t2, HWCAP_ISA_V
+	and	t2, t1, t2
+	beqz	t2, 1f
+	li      t1, RVV_MAGIC
+	addi	t2, t0,	MCONTEXT_EXTENSION
+	lw	a1, (t2)
+	bne	a1, t1, 1f
+	REG_L   t1, VCSR_OFFSET(t2)
+	csrw	vcsr, t1
+1:
+#endif
+
 	/* Note the contents of argument registers will be random
 	   unless makecontext() has been called.  */
 	RESTORE_INT_REG     (t1,   0, t0)
diff --git a/sysdeps/unix/sysv/linux/riscv/swapcontext.S b/sysdeps/unix/sysv/linux/riscv/swapcontext.S
index df0f699..94ae8e4 100644
--- a/sysdeps/unix/sysv/linux/riscv/swapcontext.S
+++ b/sysdeps/unix/sysv/linux/riscv/swapcontext.S
@@ -16,6 +16,8 @@ 
    License along with the GNU C Library.  If not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+#include <rtld-global-offsets.h>
 #include "ucontext-macros.h"
 
 /* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
@@ -40,6 +42,25 @@  LEAF (__swapcontext)
 	SAVE_INT_REG (s10, 26, a0)
 	SAVE_INT_REG (s11, 27, a0)
 
+#ifdef __riscv_vector
+#ifdef SHARED
+	la      t1, _rtld_global_ro
+	REG_L   t1, RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(t1)
+#else
+	la	t1, _dl_hwcap
+	REG_L   t1, (t1)
+#endif
+	li	t2, HWCAP_ISA_V
+	and	t2, t1, t2
+	beqz	t2, 1f
+	addi	t2, a0,	MCONTEXT_EXTENSION
+	li	t1, RVV_MAGIC
+	sw	t1, (t2)
+	csrr	t1, vcsr
+	REG_S	t1, VCSR_OFFSET(t2)
+1:
+#endif
+
 #ifndef __riscv_float_abi_soft
 	frsr a1
 
@@ -89,6 +110,26 @@  LEAF (__swapcontext)
 	fssr	t1
 #endif /* __riscv_float_abi_soft */
 
+#ifdef __riscv_vector
+#ifdef SHARED
+	la      t1, _rtld_global_ro
+	REG_L   t1, RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(t1)
+#else
+	la	t1, _dl_hwcap
+	REG_L   t1, (t1)
+#endif
+	li	t2, HWCAP_ISA_V
+	and	t2, t1, t2
+	beqz	t2, 1f
+	li      t1, RVV_MAGIC
+	addi	t2, t0,	MCONTEXT_EXTENSION
+	lw	a1, (t2)
+	bne	a1, t1, 1f
+	REG_L   t1, VCSR_OFFSET(t2)
+	csrw	vcsr, t1
+1:
+#endif
+
 	/* Note the contents of argument registers will be random
 	   unless makecontext() has been called.  */
 	RESTORE_INT_REG (t1,   0, t0)
diff --git a/sysdeps/unix/sysv/linux/riscv/sysdep.h b/sysdeps/unix/sysv/linux/riscv/sysdep.h
index 37ff07a..c9f8fd8 100644
--- a/sysdeps/unix/sysv/linux/riscv/sysdep.h
+++ b/sysdeps/unix/sysv/linux/riscv/sysdep.h
@@ -50,6 +50,7 @@ 
 
 #ifdef __ASSEMBLER__
 
+# include <bits/hwcap.h>
 # include <sys/asm.h>
 
 # define ENTRY(name) LEAF(name)
diff --git a/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym b/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym
index be55b26..4037473 100644
--- a/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym
+++ b/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym
@@ -2,6 +2,7 @@ 
 #include <signal.h>
 #include <stddef.h>
 #include <sys/ucontext.h>
+#include <asm/sigcontext.h>
 
 -- Constants used by the rt_sigprocmask call.
 
@@ -27,5 +28,10 @@  STACK_FLAGS			stack (ss_flags)
 
 MCONTEXT_GREGS			mcontext (__gregs)
 MCONTEXT_FPREGS			mcontext (__fpregs)
+MCONTEXT_EXTENSION 		mcontext (__reserved)
 
 UCONTEXT_SIZE			sizeof (ucontext_t)
+
+VCSR_OFFSET			offsetof (struct __riscv_v_state, vcsr)
+
+RVV_MAGIC