[PATCH v2 1/3] lib: sbi: Add RISC-V vector context save/restore support (eager switching)

Samuel Holland samuel.holland at sifive.com
Thu Mar 26 07:27:42 PDT 2026


Hi Dave,

On 2026-03-26 6:55 AM, dave.patel at riscstar.com wrote:
> From: Dave Patel <dave.patel at riscstar.com>
> 
> 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 |  35 ++++++++++
>  lib/sbi/objects.mk       |   7 ++
>  lib/sbi/sbi_vector.c     | 146 +++++++++++++++++++++++++++++++++++++++
>  3 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..ae151406
> --- /dev/null
> +++ b/include/sbi/sbi_vector.h
> @@ -0,0 +1,35 @@
> +/* 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>
> +
> +#ifdef CONFIG_SBI_MAX_VLENB
> +#define SBI_MAX_VLENB CONFIG_SBI_MAX_VLENB
> +#else
> +#define SBI_MAX_VLENB 256
> +#endif

You should include the corresponding Kconfig change in this patch, and then
CONFIG_SBI_MAX_VLENB will always be defined, so you will not need a fallback.

Also, you need to check vector_vlenb() against CONFIG_SBI_MAX_VLENB somewhere
during the init sequence, and refuse to boot if it is too large.

> +
> +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];
> +};

OpenSBI follows the Linux kernel coding style. All of the indentation in your
patches is incorrect. Please use scripts/checkpatch.pl on your patches.

> +
> +struct sbi_vector_context *sbi_current_vector_context(void);

This function no longer exists.

> +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/objects.mk b/lib/sbi/objects.mk
> index ea816e92..9fd378d0 100644
> --- a/lib/sbi/objects.mk
> +++ b/lib/sbi/objects.mk
> @@ -106,3 +106,10 @@ 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
> +
> +RISCV_EXTS := $(patsubst rv32%,%,$(patsubst rv64%,%,$(PLATFORM_RISCV_ISA)))
> +$(info RESULT = $(findstring v,$(RISCV_EXTS)))

This check will never succeed, because it is not safe to include "v" in the
compiler's ISA string. See commit 5545602f778e ("Makefile: Don't enable
V-extension using -march option"). You need to use ".option arch" in the inline
assembly, like in lib/sbi/sbi_trap_v_ldst.c.

> +
> +ifneq ($(findstring v,$(RISCV_EXTS)),)
> +libsbi-objs-y += sbi_vector.o
> +endif
> diff --git a/lib/sbi/sbi_vector.c b/lib/sbi/sbi_vector.c
> new file mode 100644
> index 00000000..e14b658c
> --- /dev/null
> +++ b/lib/sbi/sbi_vector.c
> @@ -0,0 +1,146 @@
> +/* 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>
> +
> +static inline unsigned long vector_vlenb(void)
> +{
> +    unsigned long vlenb;
> +    asm volatile ("csrr %0, vlenb" : "=r"(vlenb));
> +    return vlenb;
> +}
> +
> +void sbi_vector_save(struct sbi_vector_context *dst)
> +{
> +    if (!dst)
> +        return;
> +
> +    uint8_t *base = dst->vregs;
> +    unsigned long vlenb;
> +
> +    /* Save CSRs */
> +    asm volatile("csrr %0, vtype"  : "=r"(dst->vtype));
> +    asm volatile("csrr %0, vl"     : "=r"(dst->vl));
> +    asm volatile("csrr %0, vcsr"   : "=r"(dst->vcsr));
> +    asm volatile("csrr %0, vstart" : "=r"(dst->vstart));
> +
> +    /*
> +     * Set a known vector configuration before accessing registers.
> +     * This ensures the hardware is in a consistent state for save.
> +     */
> +    {
> +        unsigned long tmp;
> +        asm volatile("vsetvl %0, %1, %2"
> +                     : "=r"(tmp)
> +                     : "r"(dst->vl), "r"(dst->vtype));
> +    }
> +
> +    vlenb = vector_vlenb();
> +
> +#define SAVE_VREG(i) \
> +    asm volatile("vse8.v v" #i ", (%0)" :: "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;
> +    unsigned long vlenb = vector_vlenb();
> +
> +    /* Restore CSRs first */
> +    asm volatile("csrw vtype, %0"  :: "r"(src->vtype));
> +    asm volatile("csrw vl, %0"     :: "r"(src->vl));
> +    asm volatile("csrw vcsr, %0"   :: "r"(src->vcsr));
> +    asm volatile("csrw vstart, %0" :: "r"(src->vstart));
> +
> +    /* Re-establish vector state */
> +    {
> +        unsigned long tmp;
> +        asm volatile("vsetvl %0, %1, %2"
> +                     : "=r"(tmp)
> +                     : "r"(src->vl), "r"(src->vtype));
> +    }

This clobbers the CSRs you just restored. You have to restore the CSRs last.

Regards,
Samuel

> +
> +#define RESTORE_VREG(i) \
> +    asm volatile("vle8.v v" #i ", (%0)" :: "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
> +}
> --
> 2.43.0
> 




More information about the opensbi mailing list