[RFC PATCH v4 1/5] lib: sbi: Preserve hypervisor and VS state across domain switches
Theodorus Wensan Februanto
theodoruswensanfebruanto025 at gmail.com
Sat Nov 7 15:44:17 PST 2026
Save outgoing VS state before modifying S/H interrupt configuration, then restore incoming VS state after the H state exchange.
Preserve core H-extension CSRs, optional Smaia hypervisor interrupt state, and Smstateen state-enable registers.
Include hvien, hvictl, hviprio1, hviprio2, and the RV32 VS interrupt high-half CSRs.
Link: https://github.com/riscv-software-src/opensbi/issues/433
Signed-off-by: Theodorus Wensan Februanto <theodoruswensanfebruanto025 at gmail.com>
---
lib/sbi/sbi_domain_context.c | 139 ++++++++++++++++++++++++++++++++++-
1 file changed, 137 insertions(+), 2 deletions(-)
diff --git a/lib/sbi/sbi_domain_context.c b/lib/sbi/sbi_domain_context.c
index 987ac7fa..7500c391 100644
--- a/lib/sbi/sbi_domain_context.c
+++ b/lib/sbi/sbi_domain_context.c
@@ -18,9 +18,46 @@
#include <sbi/sbi_domain_context.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_trap.h>
+#include <sbi/sbi_timer.h>
#include <sbi/sbi_vector.h>
#include <sbi/sbi_fp.h>
+struct hart_context_hext {
+ unsigned long hstatus;
+ unsigned long hedeleg;
+ unsigned long hideleg;
+ unsigned long hie;
+ unsigned long hgeie;
+ u64 henvcfg;
+ unsigned long htval;
+ unsigned long htinst;
+ unsigned long hvip;
+ unsigned long hgatp;
+ /** Optional hypervisor state */
+ u64 hvien;
+ unsigned long hvictl;
+ u64 hviprio1;
+ u64 hviprio2;
+ u64 hstateen[4];
+#if __riscv_xlen == 32
+ unsigned long hidelegh;
+ unsigned long hviph;
+ unsigned long vsieh;
+ unsigned long vsiph;
+#endif
+ unsigned long hcounteren;
+ u64 htimedelta;
+ unsigned long vsstatus;
+ unsigned long vsie;
+ unsigned long vstvec;
+ unsigned long vsscratch;
+ unsigned long vsepc;
+ unsigned long vscause;
+ unsigned long vstval;
+ unsigned long vsip;
+ unsigned long vsatp;
+};
+
/** Context representation for a hart within a domain */
struct hart_context {
/** Trap-related states such as GPRs, mepc, and mstatus */
@@ -44,6 +81,8 @@ struct hart_context {
unsigned long sip;
/** Supervisor address translation and protection register */
unsigned long satp;
+
+ struct hart_context_hext hext;
/** Counter-enable register */
unsigned long scounteren;
/** Supervisor environment configuration register */
@@ -114,6 +153,7 @@ static int switch_to_next_domain_context(struct hart_context *ctx,
struct sbi_trap_context *trap_ctx;
struct sbi_domain *current_dom, *target_dom;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+ bool has_smaia = sbi_hart_has_extension(scratch, SBI_HART_EXT_SMAIA);
if (!ctx || !dom_ctx || ctx == dom_ctx)
return SBI_EINVAL;
@@ -131,6 +171,25 @@ static int switch_to_next_domain_context(struct hart_context *ctx,
sbi_hartmask_set_hartindex(hartindex, &target_dom->assigned_harts);
spin_unlock(&target_dom->assigned_harts_lock);
+ /* Save outgoing VS state before modifying S/H interrupt CSRs. */
+ if (misa_extension('H')) {
+ ctx->hext.vsstatus = csr_read(CSR_VSSTATUS);
+ ctx->hext.vsie = csr_read(CSR_VSIE);
+ ctx->hext.vstvec = csr_read(CSR_VSTVEC);
+ ctx->hext.vsscratch = csr_read(CSR_VSSCRATCH);
+ ctx->hext.vsepc = csr_read(CSR_VSEPC);
+ ctx->hext.vscause = csr_read(CSR_VSCAUSE);
+ ctx->hext.vstval = csr_read(CSR_VSTVAL);
+ ctx->hext.vsip = csr_read(CSR_VSIP);
+ ctx->hext.vsatp = csr_read(CSR_VSATP);
+#if __riscv_xlen == 32
+ if (has_smaia) {
+ ctx->hext.vsieh = csr_read(CSR_VSIEH);
+ ctx->hext.vsiph = csr_read(CSR_VSIPH);
+ }
+#endif
+ }
+
/* Save current CSR context and restore target domain's CSR context */
ctx->sstatus = csr_swap(CSR_SSTATUS, dom_ctx->sstatus);
ctx->sie = csr_swap(CSR_SIE, dom_ctx->sie);
@@ -141,10 +200,86 @@ static int switch_to_next_domain_context(struct hart_context *ctx,
ctx->stval = csr_swap(CSR_STVAL, dom_ctx->stval);
ctx->sip = csr_swap(CSR_SIP, dom_ctx->sip);
ctx->satp = csr_swap(CSR_SATP, dom_ctx->satp);
+ /* Save SENVCFG before changing HENVCFG. */
+ if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
+ ctx->senvcfg = csr_read(CSR_SENVCFG);
+
+ if (misa_extension('H')) {
+ ctx->hext.hstatus = csr_swap(CSR_HSTATUS, dom_ctx->hext.hstatus);
+ ctx->hext.hedeleg = csr_swap(CSR_HEDELEG, dom_ctx->hext.hedeleg);
+ ctx->hext.hideleg = csr_swap(CSR_HIDELEG, dom_ctx->hext.hideleg);
+ ctx->hext.hie = csr_swap(CSR_HIE, dom_ctx->hext.hie);
+ ctx->hext.hgeie = csr_swap(CSR_HGEIE, dom_ctx->hext.hgeie);
+ if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
+ ctx->hext.henvcfg = csr_swap64(CSR_HENVCFG,
+ dom_ctx->hext.henvcfg);
+ ctx->hext.htval = csr_swap(CSR_HTVAL, dom_ctx->hext.htval);
+ ctx->hext.htinst = csr_swap(CSR_HTINST, dom_ctx->hext.htinst);
+ ctx->hext.hvip = csr_swap(CSR_HVIP, dom_ctx->hext.hvip);
+ ctx->hext.hgatp = csr_swap(CSR_HGATP, dom_ctx->hext.hgatp);
+ ctx->hext.hcounteren = csr_swap(CSR_HCOUNTEREN, dom_ctx->hext.hcounteren);
+ if (sbi_hart_has_extension(scratch, SBI_HART_EXT_ZICNTR)) {
+ ctx->hext.htimedelta = csr_swap64(CSR_HTIMEDELTA,
+ dom_ctx->hext.htimedelta);
+ } else {
+ u64 old_delta = sbi_timer_get_delta();
+
+ sbi_timer_set_delta(dom_ctx->hext.htimedelta);
+#if __riscv_xlen == 32
+ sbi_timer_set_delta_upper(dom_ctx->hext.htimedelta >> 32);
+#endif
+ ctx->hext.htimedelta = old_delta;
+ }
+ if (has_smaia) {
+#if __riscv_xlen == 32
+ ctx->hext.hidelegh = csr_swap(CSR_HIDELEGH,
+ dom_ctx->hext.hidelegh);
+ ctx->hext.hviph = csr_swap(CSR_HVIPH,
+ dom_ctx->hext.hviph);
+#endif
+ ctx->hext.hvien = csr_swap64(CSR_HVIEN,
+ dom_ctx->hext.hvien);
+ ctx->hext.hvictl = csr_swap(CSR_HVICTL,
+ dom_ctx->hext.hvictl);
+ ctx->hext.hviprio1 = csr_swap64(CSR_HVIPRIO1,
+ dom_ctx->hext.hviprio1);
+ ctx->hext.hviprio2 = csr_swap64(CSR_HVIPRIO2,
+ dom_ctx->hext.hviprio2);
+ }
+
+ if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMSTATEEN)) {
+ ctx->hext.hstateen[0] = csr_swap64(CSR_HSTATEEN0,
+ dom_ctx->hext.hstateen[0]);
+ ctx->hext.hstateen[1] = csr_swap64(CSR_HSTATEEN1,
+ dom_ctx->hext.hstateen[1]);
+ ctx->hext.hstateen[2] = csr_swap64(CSR_HSTATEEN2,
+ dom_ctx->hext.hstateen[2]);
+ ctx->hext.hstateen[3] = csr_swap64(CSR_HSTATEEN3,
+ dom_ctx->hext.hstateen[3]);
+ }
+ /* Restore incoming VS state after H interrupt configuration. */
+ csr_write(CSR_VSSTATUS, dom_ctx->hext.vsstatus);
+ csr_write(CSR_VSIE, dom_ctx->hext.vsie);
+ csr_write(CSR_VSTVEC, dom_ctx->hext.vstvec);
+ csr_write(CSR_VSSCRATCH, dom_ctx->hext.vsscratch);
+ csr_write(CSR_VSEPC, dom_ctx->hext.vsepc);
+ csr_write(CSR_VSCAUSE, dom_ctx->hext.vscause);
+ csr_write(CSR_VSTVAL, dom_ctx->hext.vstval);
+ csr_write(CSR_VSIP, dom_ctx->hext.vsip);
+ csr_write(CSR_VSATP, dom_ctx->hext.vsatp);
+#if __riscv_xlen == 32
+ if (has_smaia) {
+ csr_write(CSR_VSIEH, dom_ctx->hext.vsieh);
+ csr_write(CSR_VSIPH, dom_ctx->hext.vsiph);
+ }
+#endif
+ }
+ /* Restore SENVCFG after the incoming HENVCFG is active. */
+ if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
+ csr_write(CSR_SENVCFG, dom_ctx->senvcfg);
+
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
ctx->scounteren = csr_swap(CSR_SCOUNTEREN, dom_ctx->scounteren);
- if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
- ctx->senvcfg = csr_swap(CSR_SENVCFG, dom_ctx->senvcfg);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSQOSID))
ctx->srmcfg = csr_swap(CSR_SRMCFG, dom_ctx->srmcfg);
--
2.43.0
More information about the opensbi
mailing list