[PATCH 1/2] riscv: Add CSR detection support
Heinrich Schuchardt
xypron.glpk at gmx.de
Tue Mar 24 19:55:35 CET 2026
Am 19. März 2026 09:29:10 MEZ schrieb Leo Yu-Chi Liang <ycliang at andestech.com>:
>Add a lightweight mechanism to safely probe CSRs that may not exist
>on the current hart. This is useful for detecting optional extensions
>(e.g. Smstateen) without relying on MARCHID or ISA string parsing.
>
>The implementation consists of:
>- A minimal expected trap handler (__riscv_expected_trap) that advances
> past the faulting instruction and signals the trap via register a4.
>- csr_read_allowed() and csr_write_allowed() macros that temporarily
> swap the trap vector, attempt the CSR access, and report whether it
> trapped.
>
>Ported from OpenSBI's sbi_csr_detect.h mechanism.
We already have a more generic mechanism for catching exceptions on RISC-V. See functions riscv_zkr_bind() and set_resume().
Do we really need a second mechanism?
Best regards
Heinrich
>
>Signed-off-by: Leo Yu-Chi Liang <ycliang at andestech.com>
>---
> arch/riscv/include/asm/csr_detect.h | 90 +++++++++++++++++++++++++++++
> arch/riscv/lib/Makefile | 1 +
> arch/riscv/lib/csr_detect.S | 23 ++++++++
> 3 files changed, 114 insertions(+)
> create mode 100644 arch/riscv/include/asm/csr_detect.h
> create mode 100644 arch/riscv/lib/csr_detect.S
>
>diff --git a/arch/riscv/include/asm/csr_detect.h b/arch/riscv/include/asm/csr_detect.h
>new file mode 100644
>index 00000000000..c058b6b85ea
>--- /dev/null
>+++ b/arch/riscv/include/asm/csr_detect.h
>@@ -0,0 +1,90 @@
>+/* SPDX-License-Identifier: GPL-2.0+ */
>+/*
>+ * Copyright (C) 2026 Andes Technology Corporation
>+ * Leo Yu-Chi Liang <ycliang at andestech.com>
>+ *
>+ * RISC-V CSR detection support
>+ *
>+ * Provides macros to safely probe CSRs that may not exist on the
>+ * current hart. Uses a lightweight trap handler that simply advances
>+ * past the faulting instruction and sets a flag.
>+ *
>+ * Ported from OpenSBI's sbi_csr_detect.h.
>+ */
>+
>+#ifndef _ASM_RISCV_CSR_DETECT_H
>+#define _ASM_RISCV_CSR_DETECT_H
>+
>+#include <asm/csr.h>
>+
>+#ifndef __ASSEMBLY__
>+
>+/* Two-level stringification so CSR macros are expanded before quoting */
>+#define __CSR_DETECT_XSTR(x) #x
>+#define __CSR_DETECT_STR(x) __CSR_DETECT_XSTR(x)
>+
>+#if CONFIG_IS_ENABLED(RISCV_SMODE)
>+#define CSR_XTVEC CSR_STVEC
>+#else
>+#define CSR_XTVEC CSR_MTVEC
>+#endif
>+
>+void __riscv_expected_trap(void);
>+
>+/**
>+ * csr_read_allowed() - Read a CSR, detecting illegal-instruction traps.
>+ * @csr_num: CSR number (must be a compile-time constant).
>+ * @trap: lvalue that is set to 1 if the access trapped, 0 otherwise.
>+ *
>+ * Returns the CSR value on success, or 0 if the CSR does not exist.
>+ *
>+ * This works by temporarily installing a minimal trap handler that
>+ * skips the faulting instruction and sets register a4 to 1. Interrupts
>+ * must be disabled when calling this macro (they normally are during
>+ * early init).
>+ */
>+#define csr_read_allowed(csr_num, trap) \
>+({ \
>+ register unsigned long __mtvec = \
>+ (unsigned long)__riscv_expected_trap; \
>+ register unsigned long __trap asm("a4") = 0; \
>+ register unsigned long __ret = 0; \
>+ __asm__ __volatile__( \
>+ "csrrw %[mtvec], " \
>+ __CSR_DETECT_STR(CSR_XTVEC) ", %[mtvec]\n" \
>+ "csrr %[ret], " __ASM_STR(csr_num) "\n" \
>+ "csrw " __CSR_DETECT_STR(CSR_XTVEC) ", %[mtvec]" \
>+ : [mtvec] "+&r"(__mtvec), [ret] "=&r"(__ret), \
>+ [trap] "+&r"(__trap) \
>+ : \
>+ : "memory"); \
>+ trap = __trap; \
>+ __ret; \
>+})
>+
>+/**
>+ * csr_write_allowed() - Write a CSR, detecting illegal-instruction traps.
>+ * @csr_num: CSR number (must be a compile-time constant).
>+ * @trap: lvalue that is set to 1 if the access trapped, 0 otherwise.
>+ * @value: Value to write.
>+ */
>+#define csr_write_allowed(csr_num, trap, value) \
>+({ \
>+ register unsigned long __mtvec = \
>+ (unsigned long)__riscv_expected_trap; \
>+ register unsigned long __trap asm("a4") = 0; \
>+ register unsigned long __val = (unsigned long)(value); \
>+ __asm__ __volatile__( \
>+ "csrrw %[mtvec], " \
>+ __CSR_DETECT_STR(CSR_XTVEC) ", %[mtvec]\n" \
>+ "csrw " __ASM_STR(csr_num) ", %[val]\n" \
>+ "csrw " __CSR_DETECT_STR(CSR_XTVEC) ", %[mtvec]" \
>+ : [mtvec] "+&r"(__mtvec), [trap] "+&r"(__trap) \
>+ : [val] "rK"(__val) \
>+ : "memory"); \
>+ trap = __trap; \
>+})
>+
>+#endif /* !__ASSEMBLY__ */
>+
>+#endif /* _ASM_RISCV_CSR_DETECT_H */
>diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
>index a527b3e9ae3..42463b8bed0 100644
>--- a/arch/riscv/lib/Makefile
>+++ b/arch/riscv/lib/Makefile
>@@ -12,6 +12,7 @@ obj-$(CONFIG_$(PHASE_)LIB_BOOTM) += bootm.o
> obj-$(CONFIG_$(PHASE_)LIB_BOOTI) += image.o
> obj-$(CONFIG_CMD_GO) += boot.o
> obj-y += cache.o
>+obj-y += csr_detect.o
> obj-$(CONFIG_SIFIVE_CACHE) += sifive_cache.o
> obj-$(CONFIG_SYS_CACHE_THEAD_CMO) += thead_cmo.o
> ifeq ($(CONFIG_$(PHASE_)RISCV_MMODE),y)
>diff --git a/arch/riscv/lib/csr_detect.S b/arch/riscv/lib/csr_detect.S
>new file mode 100644
>index 00000000000..69c4b8e7933
>--- /dev/null
>+++ b/arch/riscv/lib/csr_detect.S
>@@ -0,0 +1,23 @@
>+/* SPDX-License-Identifier: GPL-2.0+ */
>+/*
>+ * RISC-V CSR detection support
>+ *
>+ * Copyright (C) 2025 Andes Technology Corporation
>+ * Leo Yu-Chi Liang <ycliang at andestech.com>
>+ *
>+ * Ported from OpenSBI's expected trap mechanism.
>+ */
>+
>+#include <asm/encoding.h>
>+
>+ .text
>+ .align 2
>+ .global __riscv_expected_trap
>+__riscv_expected_trap:
>+ /* Advance past the faulting instruction */
>+ csrr a4, MODE_PREFIX(epc)
>+ addi a4, a4, 4
>+ csrw MODE_PREFIX(epc), a4
>+ /* Set a4 = 1 to signal that a trap occurred */
>+ li a4, 1
>+ MODE_PREFIX(ret)
More information about the U-Boot
mailing list