[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