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

dave.patel at riscstar.com dave.patel at riscstar.com
Mon Mar 30 22:58:55 PDT 2026


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 vl, vtype, vcsr CSRs along with storage for all
32 vector registers. The register state is saved and restored using byte-wise
vector load/store instructions (vse8.v/vle8.v), making the implementation
independent of current SEW/LMUL configuration.

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 |  30 ++++++
 lib/sbi/Kconfig          |   4 +
 lib/sbi/objects.mk       |   1 +
 lib/sbi/sbi_vector.c     | 215 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 250 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..4ecfaa0b
--- /dev/null
+++ b/include/sbi/sbi_vector.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * 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 vl;
+	unsigned long vtype;
+	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);
+
+#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 ea816e92..5c0caf39 100644
--- a/lib/sbi/objects.mk
+++ b/lib/sbi/objects.mk
@@ -106,3 +106,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..497d7f94
--- /dev/null
+++ b/lib/sbi/sbi_vector.c
@@ -0,0 +1,215 @@
+/* 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>
+
+#ifdef OPENSBI_CC_SUPPORT_VECTOR
+
+static inline void vsetvl(ulong vl, ulong vtype)
+{
+    ulong tmp;
+
+    asm volatile(
+	".option push\n\t"
+	".option arch, +v\n\t"
+	"vsetvl %0, %1, %2\n\t"
+	".option pop\n\t"
+	: "=r"(tmp)
+	: "r"(vl), "r"(vtype)
+	: "memory");
+}
+
+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) (				\
+	do {						\
+		asm volatile(				\
+			"	.option push\n\t"	\
+			"	.option arch, +v\n\t"	\
+			"	csrr %0, " #csr "\n\t"	\
+			"	.option pop\n\t"	\
+			:	"=r"(dst)		\
+			:				\
+			:	"memory");		\
+	} while (0))
+
+	/* Step 1: Save CSRs */
+	READ_CSR(dst->vtype,  vtype);
+	READ_CSR(dst->vl,     vl);
+	READ_CSR(dst->vcsr,   vcsr);
+	READ_CSR(dst->vstart, vstart);
+
+#undef READ_CSR
+
+	/*
+	 * Step 2: Set a known vector configuration before accessing registers.
+	 * This ensures the hardware is in a consistent state for save.
+	 */
+	vsetvl(dst->vl, dst->vtype);
+
+	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"			\
+		"	vse8.v v" #i ", (%0)\n\t"		\
+		"	.option pop\n\t"			\
+		::	"r"(base + (i) * vlenb)	: "memory"))
+
+	SAVE_VREG(0);
+	SAVE_VREG(1);
+	SAVE_VREG(2);
+	SAVE_VREG(3);
+	SAVE_VREG(4);
+	SAVE_VREG(5);
+	SAVE_VREG(6);
+	SAVE_VREG(7);
+	SAVE_VREG(8);
+	SAVE_VREG(9);
+	SAVE_VREG(10);
+	SAVE_VREG(11);
+	SAVE_VREG(12);
+	SAVE_VREG(13);
+	SAVE_VREG(14);
+	SAVE_VREG(15);
+	SAVE_VREG(16);
+	SAVE_VREG(17);
+	SAVE_VREG(18);
+	SAVE_VREG(19);
+	SAVE_VREG(20);
+	SAVE_VREG(21);
+	SAVE_VREG(22);
+	SAVE_VREG(23);
+	SAVE_VREG(24);
+	SAVE_VREG(25);
+	SAVE_VREG(26);
+	SAVE_VREG(27);
+	SAVE_VREG(28);
+	SAVE_VREG(29);
+	SAVE_VREG(30);
+	SAVE_VREG(31);
+
+#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 1: Set a known vector configuration BEFORE touching registers.
+	 * This avoids clobbering the restored CSRs later.
+	 */
+	vsetvl(src->vl, src->vtype);
+
+	/* Step 2: Restore vector registers */
+#define RESTORE_VREG(i) (					\
+	asm volatile(						\
+		"	.option push\n\t"			\
+		"	.option arch, +v\n\t"			\
+		"	vle8.v v" #i ", (%0)\n\t"		\
+		"	.option pop\n\t"			\
+		::	"r"(base + (i) * vlenb) : "memory"))
+
+	RESTORE_VREG(0);
+	RESTORE_VREG(1);
+	RESTORE_VREG(2);
+	RESTORE_VREG(3);
+	RESTORE_VREG(4);
+	RESTORE_VREG(5);
+	RESTORE_VREG(6);
+	RESTORE_VREG(7);
+	RESTORE_VREG(8);
+	RESTORE_VREG(9);
+	RESTORE_VREG(10);
+	RESTORE_VREG(11);
+	RESTORE_VREG(12);
+	RESTORE_VREG(13);
+	RESTORE_VREG(14);
+	RESTORE_VREG(15);
+	RESTORE_VREG(16);
+	RESTORE_VREG(17);
+	RESTORE_VREG(18);
+	RESTORE_VREG(19);
+	RESTORE_VREG(20);
+	RESTORE_VREG(21);
+	RESTORE_VREG(22);
+	RESTORE_VREG(23);
+	RESTORE_VREG(24);
+	RESTORE_VREG(25);
+	RESTORE_VREG(26);
+	RESTORE_VREG(27);
+	RESTORE_VREG(28);
+	RESTORE_VREG(29);
+	RESTORE_VREG(30);
+	RESTORE_VREG(31);
+#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(vtype,  src->vtype);
+	WRITE_CSR(vl,     src->vl);
+	WRITE_CSR(vcsr,   src->vcsr);
+	WRITE_CSR(vstart, src->vstart);
+#undef WRITE_CSR
+}
+
+#else
+
+void sbi_vector_save(struct sbi_vector_context *dst)
+{
+	return;
+}
+
+void sbi_vector_restore(const struct sbi_vector_context *src)
+{
+	return;
+}
+
+#endif /* OPENSBI_CC_SUPPORT_VECTOR */
--
2.43.0




More information about the opensbi mailing list