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

Anup Patel anup at brainfault.org
Sun May 17 08:37:34 PDT 2026


On Sun, May 17, 2026 at 3:51 AM <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.
>
> Signed-off-by: Dave Patel <dave.patel at riscstar.com>
> ---
>  include/sbi/sbi_vector.h |  28 ++++++++
>  lib/sbi/objects.mk       |   1 +
>  lib/sbi/sbi_vector.c     | 138 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 167 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..bbd857c3
> --- /dev/null
> +++ b/include/sbi/sbi_vector.h
> @@ -0,0 +1,28 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * 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>
> +
> +struct sbi_vector_context {
> +       unsigned long vcsr;
> +       unsigned long vstart;
> +
> +       /* size depends on VLEN */
> +       uint8_t vregs[];
> +};
> +
> +void sbi_vector_save(struct sbi_vector_context *dst);
> +void sbi_vector_restore(const struct sbi_vector_context *src);
> +unsigned long vector_vlenb(void);
> +
> +#endif //__SBI_VECTOR_H__
> +
> diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
> index 97cc4521..ddb2e7ac 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..c596ec7a
> --- /dev/null
> +++ b/lib/sbi/sbi_vector.c
> @@ -0,0 +1,138 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * 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
> +
> +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;

This whole function can be a single statement "csr_read(CSR_VLENB);"

Introduce new function sbi_vector_context_size() over here which
estimates vector context size over here so that all vector context
related code is in one place.

size_t sbi_vector_context_size(void)
{
    return sizeof(struct sbi_vector_context) + (32 * csr_read(CSR_VLENB));
}

> +}
> +
> +static inline void set_vs(void)
> +{
> +       csr_set(CSR_MSTATUS, MSTATUS_VS);
> +}
> +
> +void sbi_vector_save(struct sbi_vector_context *dst)
> +{
> +       if (!dst)
> +               return;
> +
> +       unsigned long mstatus_orig;

Move all variable declarations at the start of function.

> +       /* Step 1. Save original mstatus */
> +       asm volatile("csrr %0, mstatus" : "=r"(mstatus_orig));
> +
> +       /* Step 2. Enable VS */
> +       set_vs();

These two lines can be just one once CSR operation:
mstatus_orig = csr_read_set(CSR_MSTATUS, MSTATUS_VS);

> +
> +       /* Step 3: Save CSRs */
> +       dst->vcsr = csr_read(vcsr);
> +       dst->vstart = csr_read(vstart);
> +
> +       ulong vlenb = vector_vlenb();
> +       uint8_t *base = dst->vregs;
> +
> +       /* Step 4: 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
> +
> +       /* Step 5. Restore original mstatus LAST */
> +       asm volatile("csrw mstatus, %0" :: "r"(mstatus_orig));

csr_write(CSR_MSTATUS, mstatus_orig);

> +}
> +
> +void sbi_vector_restore(const struct sbi_vector_context *src)
> +{
> +       if (!src)
> +               return;
> +
> +       unsigned long mstatus_orig;

Move all variable declarations at the start of function.

> +       /* Step 1. Save original mstatus */
> +       asm volatile("csrr %0, mstatus" : "=r"(mstatus_orig));
> +
> +       /* Step 2. Enable VS */
> +       set_vs();

Same comment as above.

> +
> +       const uint8_t *base = src->vregs;
> +       ulong vlenb = vector_vlenb();
> +
> +       /* Step 3: 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 4: Restore CSR's last */
> +       /* Restore CSRs first */
> +       csr_write(vcsr,   src->vcsr);
> +       csr_write(vstart, src->vstart);
> +
> +       /* Step 5. Restore original mstatus LAST */
> +       asm volatile("csrw mstatus, %0" :: "r"(mstatus_orig));

Same comment as above.

> +}
> +
> +#else
> +
> +void sbi_vector_save(struct sbi_vector_context *dst)
> +{
> +}
> +
> +void sbi_vector_restore(const struct sbi_vector_context *src)
> +{
> +}
> +
> +unsigned long vector_vlenb(void)
> +{
> +       return 0;
> +}

size_t sbi_vector_context_size(void)
{
     return 0;
}

> +#endif /* OPENSBI_CC_SUPPORT_VECTOR */
> --
> 2.43.0
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi

Regards,
Anup



More information about the opensbi mailing list