@@ -457,6 +457,16 @@ config RISCV_ISA_C
If you don't know what to do here, say Y.
+config RISCV_ISA_SSDTSO
+ bool "Ssdtso extension support for dynamic TSO memory ordering"
+ default y
+ help
+ Adds support to dynamically detect the presence of the Ssdtso
+ ISA-extension and allows user-space processes to activate/deactivate
+ the TSO memory ordering model at run-time.
+
+ If you don't know what to do here, say Y.
+
config RISCV_ISA_SVNAPOT
bool "Svnapot extension support for supervisor mode NAPOT pages"
depends on 64BIT && MMU
@@ -194,6 +194,7 @@
/* xENVCFG flags */
#define ENVCFG_STCE (_AC(1, ULL) << 63)
#define ENVCFG_PBMTE (_AC(1, ULL) << 62)
+#define ENVCFG_DTSO (_AC(1, UL) << 8)
#define ENVCFG_CBZE (_AC(1, UL) << 7)
#define ENVCFG_CBCFE (_AC(1, UL) << 6)
#define ENVCFG_CBIE_SHIFT 4
new file mode 100644
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Christoph Muellner <christoph.muellner@vrull.eu>
+ */
+
+#ifndef __ASM_RISCV_DTSO_H
+#define __ASM_RISCV_DTSO_H
+
+#ifdef CONFIG_RISCV_ISA_SSDTSO
+
+#include <linux/sched/task_stack.h>
+#include <asm/cpufeature.h>
+#include <asm/csr.h>
+
+static __always_inline bool has_dtso(void)
+{
+ return riscv_has_extension_unlikely(RISCV_ISA_EXT_SSDTSO);
+}
+
+static inline bool dtso_is_enabled(void)
+{
+ if (has_dtso())
+ return csr_read(CSR_SENVCFG) & ENVCFG_DTSO;
+ return 0;
+}
+
+static inline void dtso_disable(void)
+{
+ if (has_dtso())
+ csr_clear(CSR_SENVCFG, ENVCFG_DTSO);
+}
+
+static inline void dtso_enable(void)
+{
+ if (has_dtso())
+ csr_set(CSR_SENVCFG, ENVCFG_DTSO);
+}
+
+static inline void dtso_save(struct task_struct *task)
+{
+ task->thread.dtso_ena = dtso_is_enabled();
+}
+
+static inline void dtso_restore(struct task_struct *task)
+{
+ if (task->thread.dtso_ena)
+ dtso_enable();
+ else
+ dtso_disable();
+}
+
+static inline void __switch_to_dtso(struct task_struct *prev,
+ struct task_struct *next)
+{
+ struct pt_regs *regs;
+
+ regs = task_pt_regs(prev);
+ dtso_save(prev);
+ dtso_restore(next);
+}
+
+#else /* ! CONFIG_RISCV_ISA_SSDTSO */
+
+static __always_inline bool has_dtso(void) { return false; }
+static __always_inline bool dtso_is_enabled(void) { return false; }
+#define dtso_disable() do { } while (0)
+#define dtso_enable() do { } while (0)
+#define dtso_save(task) do { } while (0)
+#define dtso_restore(task) do { } while (0)
+#define __switch_to_dtso(prev, next) do { } while (0)
+
+#endif /* CONFIG_RISCV_ISA_SSDTSO */
+
+#endif /* ! __ASM_RISCV_DTSO_H */
@@ -57,6 +57,7 @@
#define RISCV_ISA_EXT_ZIHPM 42
#define RISCV_ISA_EXT_SMSTATEEN 43
#define RISCV_ISA_EXT_ZICOND 44
+#define RISCV_ISA_EXT_SSDTSO 45
#define RISCV_ISA_EXT_MAX 64
@@ -84,6 +84,7 @@ struct thread_struct {
unsigned long vstate_ctrl;
struct __riscv_v_ext_state vstate;
unsigned long align_ctl;
+ bool dtso_ena; /* Dynamic TSO enable */
};
/* Whitelist the fstate from the task_struct for hardened usercopy */
@@ -9,6 +9,7 @@
#include <linux/jump_label.h>
#include <linux/sched/task_stack.h>
#include <asm/vector.h>
+#include <asm/dtso.h>
#include <asm/cpufeature.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
@@ -81,6 +82,8 @@ do { \
__switch_to_fpu(__prev, __next); \
if (has_vector()) \
__switch_to_vector(__prev, __next); \
+ if (has_dtso()) \
+ __switch_to_dtso(__prev, __next); \
((last) = __switch_to(__prev, __next)); \
} while (0)
@@ -181,6 +181,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
__RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN),
__RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
+ __RISCV_ISA_EXT_DATA(ssdtso, RISCV_ISA_EXT_SSDTSO),
__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
__RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
__RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT),
@@ -172,6 +172,10 @@ void flush_thread(void)
kfree(current->thread.vstate.datap);
memset(¤t->thread.vstate, 0, sizeof(struct __riscv_v_ext_state));
#endif
+#ifdef CONFIG_RISCV_ISA_SSDTSO
+ /* Reset DTSO state */
+ current->thread.dtso_ena = false;
+#endif
}
void arch_release_task_struct(struct task_struct *tsk)