]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
riscv: Add support for per-thread envcfg CSR values
authorSamuel Holland <samuel.holland@sifive.com>
Wed, 14 Aug 2024 08:10:55 +0000 (01:10 -0700)
committerPalmer Dabbelt <palmer@rivosinc.com>
Sat, 5 Oct 2024 15:51:14 +0000 (08:51 -0700)
Some bits in the [ms]envcfg CSR, such as the CFI state and pointer
masking mode, need to be controlled on a per-thread basis. Support this
by keeping a copy of the CSR value in struct thread_struct and writing
it during context switches. It is safe to discard the old CSR value
during the context switch because the CSR is modified only by software,
so the CSR will remain in sync with the copy in thread_struct.

Use ALTERNATIVE directly instead of riscv_has_extension_unlikely() to
minimize branchiness in the context switching code.

Since thread_struct is copied during fork(), setting the value for the
init task sets the default value for all other threads.

Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Deepak Gupta <debug@rivosinc.com>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
Link: https://lore.kernel.org/r/20240814081126.956287-3-samuel.holland@sifive.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
arch/riscv/include/asm/processor.h
arch/riscv/include/asm/switch_to.h
arch/riscv/kernel/cpufeature.c

index efa1b3519b23801d1a998f72830129eaf66ca90a..c1a492508835314ad39caaa63bc8535dff2b118d 100644 (file)
@@ -102,6 +102,7 @@ struct thread_struct {
        unsigned long s[12];    /* s[0]: frame pointer */
        struct __riscv_d_ext_state fstate;
        unsigned long bad_cause;
+       unsigned long envcfg;
        u32 riscv_v_flags;
        u32 vstate_ctrl;
        struct __riscv_v_ext_state vstate;
index 7594df37cc9ff33659d610a7da3ceeecbd655a49..9685cd85e57ccd024e5cd2f6370fb9ccdfd6b4e4 100644 (file)
@@ -70,6 +70,13 @@ static __always_inline bool has_fpu(void) { return false; }
 #define __switch_to_fpu(__prev, __next) do { } while (0)
 #endif
 
+static inline void __switch_to_envcfg(struct task_struct *next)
+{
+       asm volatile (ALTERNATIVE("nop", "csrw " __stringify(CSR_ENVCFG) ", %0",
+                                 0, RISCV_ISA_EXT_XLINUXENVCFG, 1)
+                       :: "r" (next->thread.envcfg) : "memory");
+}
+
 extern struct task_struct *__switch_to(struct task_struct *,
                                       struct task_struct *);
 
@@ -103,6 +110,7 @@ do {                                                        \
                __switch_to_vector(__prev, __next);     \
        if (switch_to_should_flush_icache(__next))      \
                local_flush_icache_all();               \
+       __switch_to_envcfg(__next);                     \
        ((last) = __switch_to(__prev, __next));         \
 } while (0)
 
index e560a253e99bddb5ca841ed29ee76fb397fcd764..27bafc5dd62df6adde3c42e3fb07e19f32cacf31 100644 (file)
@@ -923,7 +923,7 @@ unsigned long riscv_get_elf_hwcap(void)
 void riscv_user_isa_enable(void)
 {
        if (riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICBOZ))
-               csr_set(CSR_ENVCFG, ENVCFG_CBZE);
+               current->thread.envcfg |= ENVCFG_CBZE;
        else if (any_cpu_has_zicboz)
                pr_warn_once("Zicboz disabled as it is unavailable on some harts\n");
 }