[RFC PATCH v2 7/8] lib: sbi: Preserve supervisor CTR records across domain switches
Theodorus Wensan Februanto
theodoruswensanfebruanto025 at gmail.com
Fri Oct 23 00:09:24 PDT 2026
Save supervisor CTR control, depth, status, and logical record
entries when Ssctr and Sscsrind are available. This experimental
implementation freezes recording before saving and restores
status before logical records.
IMSIC and other indirect CSR state remain outside this change.
Link: https://github.com/riscv-software-src/opensbi/issues/433
Signed-off-by: Theodorus Wensan Februanto <theodoruswensanfebruanto025 at gmail.com>
---
include/sbi/sbi_hart.h | 2 +
lib/sbi/sbi_domain_context.c | 100 +++++++++++++++++++++++++++++++++++
lib/sbi/sbi_hart.c | 11 ++++
3 files changed, 113 insertions(+)
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index 543393bb..171fe759 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -125,6 +125,8 @@ struct sbi_hart_features {
unsigned int pmp_log2gran;
unsigned int mhpm_mask;
unsigned int mhpm_bits;
+ unsigned long ctr_depth;
+ unsigned int ctr_num_entries;
};
extern unsigned long hart_features_offset;
diff --git a/lib/sbi/sbi_domain_context.c b/lib/sbi/sbi_domain_context.c
index 34d1bc76..b2918c9f 100644
--- a/lib/sbi/sbi_domain_context.c
+++ b/lib/sbi/sbi_domain_context.c
@@ -21,6 +21,24 @@
#include <sbi/sbi_vector.h>
#include <sbi/sbi_fp.h>
+#define HART_CTR_FIRST_SELECTOR 0x200
+#define HART_CTR_FROZEN (1UL << 31)
+
+struct hart_ctr_entry {
+ unsigned long source;
+ unsigned long target;
+ unsigned long data;
+};
+
+struct hart_ctr_context {
+ unsigned long ctl;
+ unsigned long depth;
+ unsigned long status;
+ unsigned long vsctl;
+ unsigned int num_entries;
+ struct hart_ctr_entry entries[];
+};
+
struct hart_context_hext {
unsigned long hstatus;
unsigned long hedeleg;
@@ -95,6 +113,8 @@ struct hart_context {
unsigned long siselect;
/** AIA supervisor interrupt priority register bank */
unsigned long siprio[16];
+ /** Supervisor control transfer records */
+ struct hart_ctr_context *ctr_ctx;
/** Float context state */
struct sbi_fp_context fp_ctx;
@@ -160,6 +180,63 @@ static void hart_aia_iprio_restore(const struct hart_context *ctx)
}
}
+#if __riscv_xlen == 64
+static unsigned int hart_ctr_entry_count(unsigned long depth)
+{
+ unsigned int encoding = depth & 7;
+
+ if (encoding > 4)
+ return 0;
+ return 16U << encoding;
+}
+
+static void hart_ctr_save(struct hart_ctr_context *ctx)
+{
+ unsigned int i, count;
+
+ ctx->status = csr_read_set(CSR_SCTRSTATUS, HART_CTR_FROZEN);
+ ctx->ctl = csr_read(CSR_SCTRCTL);
+ ctx->depth = csr_read(CSR_SCTRDEPTH);
+ if (misa_extension('H'))
+ ctx->vsctl = csr_read(CSR_VSCTRCTL);
+
+ count = hart_ctr_entry_count(ctx->depth);
+ if (count > ctx->num_entries)
+ count = ctx->num_entries;
+ for (i = 0; i < count; i++) {
+ csr_write(CSR_SISELECT, HART_CTR_FIRST_SELECTOR + i);
+ ctx->entries[i].source = csr_read(CSR_SIREG);
+ ctx->entries[i].target = csr_read(CSR_SIREG2);
+ ctx->entries[i].data = csr_read(CSR_SIREG3);
+ }
+}
+
+static void hart_ctr_restore(const struct hart_ctr_context *ctx)
+{
+ unsigned int i, count;
+
+ csr_write(CSR_SCTRCTL, 0);
+ csr_write(CSR_SCTRDEPTH, ctx->depth);
+ __asm__ __volatile__(".4byte 0x10400073" ::: "memory");
+ csr_write(CSR_SCTRSTATUS, ctx->status | HART_CTR_FROZEN);
+
+ count = hart_ctr_entry_count(ctx->depth);
+ if (count > ctx->num_entries)
+ count = ctx->num_entries;
+ for (i = 0; i < count; i++) {
+ csr_write(CSR_SISELECT, HART_CTR_FIRST_SELECTOR + i);
+ csr_write(CSR_SIREG2, ctx->entries[i].target);
+ csr_write(CSR_SIREG3, ctx->entries[i].data);
+ csr_write(CSR_SIREG, ctx->entries[i].source);
+ }
+
+ if (misa_extension('H'))
+ csr_write(CSR_VSCTRCTL, ctx->vsctl);
+ csr_write(CSR_SCTRCTL, ctx->ctl);
+ csr_write(CSR_SCTRSTATUS, ctx->status);
+}
+#endif
+
/**
* Switches the HART context from the current domain to the target domain.
* This includes changing domain assignments and reconfiguring PMP, as well
@@ -281,6 +358,13 @@ static int switch_to_next_domain_context(struct hart_context *ctx,
hart_aia_iprio_restore(dom_ctx);
csr_write(CSR_SISELECT, dom_ctx->siselect);
}
+#if __riscv_xlen == 64
+ if (ctx->ctr_ctx && dom_ctx->ctr_ctx) {
+ hart_ctr_save(ctx->ctr_ctx);
+ hart_ctr_restore(dom_ctx->ctr_ctx);
+ csr_write(CSR_SISELECT, dom_ctx->siselect);
+ }
+#endif
/* Eager context switch for float */
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_F) ||
@@ -331,6 +415,8 @@ static int hart_context_init(u32 hartindex)
{
size_t vec_size;
struct hart_context *ctx;
+ struct sbi_hart_features *hart_features =
+ sbi_hart_features_ptr(sbi_scratch_thishart_ptr());
struct sbi_domain *dom;
sbi_domain_for_each(dom) {
@@ -345,6 +431,19 @@ static int hart_context_init(u32 hartindex)
ctx->sstc.stimecmp = ~0ULL;
ctx->sstc.vstimecmp = ~0ULL;
+#if __riscv_xlen == 64
+ if (hart_features->ctr_num_entries) {
+ ctx->ctr_ctx = sbi_zalloc(sizeof(*ctx->ctr_ctx) +
+ hart_features->ctr_num_entries * sizeof(struct hart_ctr_entry));
+ if (!ctx->ctr_ctx) {
+ sbi_free(ctx);
+ return SBI_ENOMEM;
+ }
+ ctx->ctr_ctx->depth = hart_features->ctr_depth;
+ ctx->ctr_ctx->num_entries = hart_features->ctr_num_entries;
+ }
+#endif
+
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
SBI_HART_EXT_V)) {
vec_size = sbi_vector_context_size();
@@ -352,6 +451,7 @@ static int hart_context_init(u32 hartindex)
/* Allocate the vector context pointer */
ctx->vec_ctx = sbi_zalloc(vec_size);
if (!ctx->vec_ctx) {
+ sbi_free(ctx->ctr_ctx);
sbi_free(ctx);
return SBI_ENOMEM;
}
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index bee88557..a4bbb750 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -672,6 +672,17 @@ __pmp_skip:
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_ZIHPM, true);
+#if __riscv_xlen == 64
+ if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCTR) &&
+ sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCSRIND)) {
+ val = csr_read_allowed(CSR_SCTRDEPTH, &trap);
+ if (!trap.cause && (val & 7) <= 4) {
+ hfeatures->ctr_depth = val;
+ hfeatures->ctr_num_entries = 16U << (val & 7);
+ }
+ }
+#endif
+
/* Mark hart feature detection done */
hfeatures->detected = true;
--
2.43.0
More information about the opensbi
mailing list