[PATCH v4 1/3] lib: sbi: Add RISC-V vector context save/restore support

Samuel Holland samuel.holland at sifive.com
Mon Apr 6 15:39:58 PDT 2026


Hi Dave,

On 2026-04-06 2:31 PM, dave.patel at riscstar.com wrote:
> From: Dave Patel <dave.patel at riscstar.com>
> 
> Eager context switch: Add support for saving and restoring RISC-V vector
> extension state in OpenSBI. This introduces a per-hart vector context
> structure and helper routines to perform full context save and restore.
> 
> The vector context includes vcsr CSRs along with storage for all 32 vector
> registers. The register state is saved and restored using byte-wise vector
> load/store instructions (vs8r/vl8r).
> 
> The implementation follows an eager context switching model where the entire
> vector state is saved and restored on every context switch. This provides a
> simple and deterministic mechanism without requiring lazy trap-based
> management.
> 
> Notes:
> - The SBI_MAX_VLENB is configured using CONFIG_SBI_MAX_VLENB.
> 
> Signed-off-by: Dave Patel <dave.patel at riscstar.com>
> ---
>  include/sbi/sbi_vector.h |  29 ++++++++
>  lib/sbi/Kconfig          |   4 +
>  lib/sbi/objects.mk       |   1 +
>  lib/sbi/sbi_vector.c     | 154 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 188 insertions(+)
>  create mode 100644 include/sbi/sbi_vector.h
>  create mode 100644 lib/sbi/sbi_vector.c
> 
> diff --git a/include/sbi/sbi_vector.h b/include/sbi/sbi_vector.h
> new file mode 100644
> index 00000000..13048716
> --- /dev/null
> +++ b/include/sbi/sbi_vector.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: GPL-2.0

This license is not compatible with the OpenSBI project. You need to release
these changes under a compatible license (assuming you are able to do so, i.e.
they are not derived from GPL code, etc. I am not a lawyer).

> + *
> + * Copyright (c) 2026 RISCstar Solutions.
> + *
> + * Authors:
> + *   Dave Patel <dave.patel at riscstar.com>
> + */
> +
> +#ifndef __SBI_VECTOR_H__
> +#define __SBI_VECTOR_H__
> +
> +#include <sbi/sbi_types.h>
> +
> +#define SBI_MAX_VLENB CONFIG_SBI_MAX_VLENB
> +
> +struct sbi_vector_context {
> +	unsigned long vcsr;
> +	unsigned long vstart;
> +
> +	/* size depends on VLEN */
> +	uint8_t vregs[32 * SBI_MAX_VLENB];
> +};
> +
> +void sbi_vector_save(struct sbi_vector_context *dst);
> +void sbi_vector_restore(const struct sbi_vector_context *src);
> +int sbi_vector_domain_init(void);
> +
> +#endif //__SBI_VECTOR_H__
> +
> diff --git a/lib/sbi/Kconfig b/lib/sbi/Kconfig
> index 8479f861..b2432150 100644
> --- a/lib/sbi/Kconfig
> +++ b/lib/sbi/Kconfig
> @@ -74,4 +74,8 @@ config SBI_ECALL_VIRQ
>  	bool "VIRQ extension"
>  	default y
> 
> +config SBI_MAX_VLENB
> +	int "Vector VLENB size"
> +	default 256
> +
>  endmenu
> diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
> index 68fc2036..ecb2b54e 100644
> --- a/lib/sbi/objects.mk
> +++ b/lib/sbi/objects.mk
> @@ -109,3 +109,4 @@ libsbi-objs-y += sbi_trap_v_ldst.o
>  libsbi-objs-y += sbi_unpriv.o
>  libsbi-objs-y += sbi_expected_trap.o
>  libsbi-objs-y += sbi_cppc.o
> +libsbi-objs-y += sbi_vector.o
> diff --git a/lib/sbi/sbi_vector.c b/lib/sbi/sbi_vector.c
> new file mode 100644
> index 00000000..85134f8b
> --- /dev/null
> +++ b/lib/sbi/sbi_vector.c
> @@ -0,0 +1,154 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * Copyright (c) 2026 RISCstar Solutions.
> + *
> + * Authors:
> + *	 Dave Patel <dave.patel at riscstar.com>
> + */
> +
> +#include <sbi/sbi_domain.h>
> +#include <sbi/riscv_encoding.h>
> +#include <sbi/riscv_asm.h>
> +#include <sbi/sbi_vector.h>
> +#include <sbi/sbi_types.h>
> +#include <sbi/sbi_hart.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_console.h>
> +
> +#ifdef OPENSBI_CC_SUPPORT_VECTOR
> +
> +static inline unsigned long vector_vlenb(void)
> +{
> +	unsigned long vlenb = 0;
> +
> +	asm volatile (
> +		".option push\n\t"
> +		".option arch, +v\n\t"
> +		"csrr %0, vlenb\n\t"
> +		".option pop\n\t"
> +		: "=r"(vlenb)
> +		:
> +		: "memory");
> +
> +	return vlenb;
> +}
> +
> +void sbi_vector_save(struct sbi_vector_context *dst)
> +{
> +	if (!dst)
> +		return;
> +
> +#define READ_CSR(dst, csr)				\
> +	({						\
> +		asm volatile (				\
> +			"	.option push\n\t"	\
> +			"	.option arch, +v\n\t"	\
> +			"	csrr %0, " #csr "\n\t"	\
> +			"	.option pop\n\t"	\
> +			:	"=r"(dst)		\
> +			:				\
> +			:	"memory");		\
> +	})						\
> +
> +	/* Step 1: Save CSRs */
> +	READ_CSR(dst->vcsr,   vcsr);
> +	READ_CSR(dst->vstart, vstart);
> +
> +#undef READ_CSR
> +
> +	ulong vlenb = vector_vlenb();
> +	uint8_t *base = dst->vregs;
> +
> +	/* Step 3: Save vector registers */
> +#define SAVE_VREG(i)						\
> +	({							\
> +	asm volatile(						\
> +		"	.option push\n\t"			\
> +		"	.option arch, +v\n\t"			\
> +		"	vs8r.v v" #i ", (%0)\n\t"		\
> +		"	.option pop\n\t"			\
> +		::	"r"(base + (i) * vlenb)	: "memory");	\
> +	})							\
> +
> +	SAVE_VREG(0);
> +	SAVE_VREG(8);
> +	SAVE_VREG(16);
> +	SAVE_VREG(24);
> +
> +#undef SAVE_VREG
> +}
> +
> +void sbi_vector_restore(const struct sbi_vector_context *src)
> +{
> +	if (!src)
> +		return;
> +
> +	const uint8_t *base = src->vregs;
> +	ulong vlenb = vector_vlenb();
> +
> +	/* Step 2: Restore vector registers */
> +#define RESTORE_VREG(i)					\
> +	({							\
> +	asm volatile(						\
> +		"	.option push\n\t"			\
> +		"	.option arch, +v\n\t"			\
> +		"	vl8r.v v" #i ", (%0)\n\t"		\
> +		"	.option pop\n\t"			\
> +		::	"r"(base + (i) * vlenb) : "memory");	\
> +	 })							\
> +
> +	RESTORE_VREG(0);
> +	RESTORE_VREG(8);
> +	RESTORE_VREG(16);
> +	RESTORE_VREG(24);
> +#undef RESTORE_VREG
> +
> +	/* Step 3: Restore CSR's last */
> +#define WRITE_CSR(csr, val)			\
> +	({					\
> +	asm volatile(				\
> +		"	.option push\n\t"	\
> +		"	.option arch, +v\n\t"	\
> +		"	csrw " #csr ", %0\n\t"	\
> +		"	.option pop\n\t"	\
> +		:				\
> +		:	"r"(val)		\
> +		:	"memory");		\
> +	 })					\
> +
> +	/* Restore CSRs first */
> +	WRITE_CSR(vcsr,   src->vcsr);
> +	WRITE_CSR(vstart, src->vstart);
> +#undef WRITE_CSR
> +}
> +
> +int sbi_vector_domain_init(void)
> +{
> +	csr_set(CSR_MSTATUS, MSTATUS_VS);
> +	ulong vlenb = vector_vlenb();
> +
> +	if (vlenb > SBI_MAX_VLENB) {
> +		sbi_printf("[Vector ERR:] vlenb range error\n");
> +		return SBI_ERR_BAD_RANGE;
> +	}
> +
> +	csr_clear(CSR_MSTATUS, MSTATUS_VS);

What is the purpose of this CSR write? If you want to set the initial state of
the vector registers, this doesn't accomplish that; you have to write the vector
registers.

Regards,
Samuel

> +	return SBI_OK;
> +}
> +
> +#else
> +
> +void sbi_vector_save(struct sbi_vector_context *dst)
> +{
> +}
> +
> +void sbi_vector_restore(const struct sbi_vector_context *src)
> +{
> +}
> +
> +int sbi_vector_domain_init(void)
> +{
> +	return SBI_OK;
> +}
> +
> +#endif /* OPENSBI_CC_SUPPORT_VECTOR */
> --
> 2.43.0
> 




More information about the opensbi mailing list