]> www.infradead.org Git - nvme.git/commitdiff
riscv: Fix RISCV_ALTERNATIVE_EARLY
authorAlexandre Ghiti <alexghiti@rivosinc.com>
Thu, 29 Aug 2024 16:50:48 +0000 (18:50 +0200)
committerPalmer Dabbelt <palmer@rivosinc.com>
Tue, 3 Sep 2024 14:57:55 +0000 (07:57 -0700)
RISCV_ALTERNATIVE_EARLY will issue sbi_ecall() very early in the boot
process, before the first memory mapping is setup so we can't have any
instrumentation happening here.

In addition, when the kernel is relocatable, we must also not issue any
relocation this early since they would have been patched virtually only.

So, instead of disabling instrumentation for the whole kernel/sbi.c file
and compiling it with -fno-pie, simply move __sbi_ecall() and
__sbi_base_ecall() into their own file where this is fixed.

Reported-by: Conor Dooley <conor.dooley@microchip.com>
Closes: https://lore.kernel.org/linux-riscv/20240813-pony-truck-3e7a83e9759e@spud/
Reported-by: syzbot+cfbcb82adf6d7279fd35@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/linux-riscv/00000000000065062c061fcec37b@google.com/
Fixes: 1745cfafebdf ("riscv: don't use global static vars to store alternative data")
Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Link: https://lore.kernel.org/r/20240829165048.49756-1-alexghiti@rivosinc.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
arch/riscv/include/asm/sbi.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/sbi.c
arch/riscv/kernel/sbi_ecall.c [new file with mode: 0644]

index 7cffd4ffecd0ce9be737860dc5f83a3339508b03..7bd3746028c9e2f9361c51328d9c7cf488a973a8 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/types.h>
 #include <linux/cpumask.h>
+#include <linux/jump_label.h>
 
 #ifdef CONFIG_RISCV_SBI
 enum sbi_ext_id {
@@ -304,6 +305,7 @@ struct sbiret {
 };
 
 void sbi_init(void);
+long __sbi_base_ecall(int fid);
 struct sbiret __sbi_ecall(unsigned long arg0, unsigned long arg1,
                          unsigned long arg2, unsigned long arg3,
                          unsigned long arg4, unsigned long arg5,
@@ -373,7 +375,23 @@ static inline unsigned long sbi_mk_version(unsigned long major,
                | (minor & SBI_SPEC_VERSION_MINOR_MASK);
 }
 
-int sbi_err_map_linux_errno(int err);
+static inline int sbi_err_map_linux_errno(int err)
+{
+       switch (err) {
+       case SBI_SUCCESS:
+               return 0;
+       case SBI_ERR_DENIED:
+               return -EPERM;
+       case SBI_ERR_INVALID_PARAM:
+               return -EINVAL;
+       case SBI_ERR_INVALID_ADDRESS:
+               return -EFAULT;
+       case SBI_ERR_NOT_SUPPORTED:
+       case SBI_ERR_FAILURE:
+       default:
+               return -ENOTSUPP;
+       };
+}
 
 extern bool sbi_debug_console_available;
 int sbi_debug_console_write(const char *bytes, unsigned int num_bytes);
index 06d407f1b30bc2028ffe37df3b64fd9c5a9e17e4..7f88cc4931f5c44105e827d46832a94fe81483f4 100644 (file)
@@ -20,17 +20,21 @@ endif
 ifdef CONFIG_RISCV_ALTERNATIVE_EARLY
 CFLAGS_alternative.o := -mcmodel=medany
 CFLAGS_cpufeature.o := -mcmodel=medany
+CFLAGS_sbi_ecall.o := -mcmodel=medany
 ifdef CONFIG_FTRACE
 CFLAGS_REMOVE_alternative.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_cpufeature.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_sbi_ecall.o = $(CC_FLAGS_FTRACE)
 endif
 ifdef CONFIG_RELOCATABLE
 CFLAGS_alternative.o += -fno-pie
 CFLAGS_cpufeature.o += -fno-pie
+CFLAGS_sbi_ecall.o += -fno-pie
 endif
 ifdef CONFIG_KASAN
 KASAN_SANITIZE_alternative.o := n
 KASAN_SANITIZE_cpufeature.o := n
+KASAN_SANITIZE_sbi_ecall.o := n
 endif
 endif
 
@@ -88,7 +92,7 @@ obj-$(CONFIG_DYNAMIC_FTRACE)  += mcount-dyn.o
 
 obj-$(CONFIG_PERF_EVENTS)      += perf_callchain.o
 obj-$(CONFIG_HAVE_PERF_REGS)   += perf_regs.o
-obj-$(CONFIG_RISCV_SBI)                += sbi.o
+obj-$(CONFIG_RISCV_SBI)                += sbi.o sbi_ecall.o
 ifeq ($(CONFIG_RISCV_SBI), y)
 obj-$(CONFIG_SMP)              += sbi-ipi.o
 obj-$(CONFIG_SMP) += cpu_ops_sbi.o
index 837bdab2601bd970c3a2f946026360ff80c52257..1989b8cade1b98c0ff0cb131359d7e29955b56c9 100644 (file)
@@ -14,9 +14,6 @@
 #include <asm/smp.h>
 #include <asm/tlbflush.h>
 
-#define CREATE_TRACE_POINTS
-#include <asm/trace.h>
-
 /* default SBI version is 0.1 */
 unsigned long sbi_spec_version __ro_after_init = SBI_SPEC_VERSION_DEFAULT;
 EXPORT_SYMBOL(sbi_spec_version);
@@ -27,55 +24,6 @@ static int (*__sbi_rfence)(int fid, const struct cpumask *cpu_mask,
                           unsigned long start, unsigned long size,
                           unsigned long arg4, unsigned long arg5) __ro_after_init;
 
-struct sbiret __sbi_ecall(unsigned long arg0, unsigned long arg1,
-                         unsigned long arg2, unsigned long arg3,
-                         unsigned long arg4, unsigned long arg5,
-                         int fid, int ext)
-{
-       struct sbiret ret;
-
-       trace_sbi_call(ext, fid);
-
-       register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
-       register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
-       register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
-       register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
-       register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
-       register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
-       register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
-       register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
-       asm volatile ("ecall"
-                     : "+r" (a0), "+r" (a1)
-                     : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
-                     : "memory");
-       ret.error = a0;
-       ret.value = a1;
-
-       trace_sbi_return(ext, ret.error, ret.value);
-
-       return ret;
-}
-EXPORT_SYMBOL(__sbi_ecall);
-
-int sbi_err_map_linux_errno(int err)
-{
-       switch (err) {
-       case SBI_SUCCESS:
-               return 0;
-       case SBI_ERR_DENIED:
-               return -EPERM;
-       case SBI_ERR_INVALID_PARAM:
-               return -EINVAL;
-       case SBI_ERR_INVALID_ADDRESS:
-               return -EFAULT;
-       case SBI_ERR_NOT_SUPPORTED:
-       case SBI_ERR_FAILURE:
-       default:
-               return -ENOTSUPP;
-       };
-}
-EXPORT_SYMBOL(sbi_err_map_linux_errno);
-
 #ifdef CONFIG_RISCV_SBI_V01
 static unsigned long __sbi_v01_cpumask_to_hartmask(const struct cpumask *cpu_mask)
 {
@@ -535,17 +483,6 @@ long sbi_probe_extension(int extid)
 }
 EXPORT_SYMBOL(sbi_probe_extension);
 
-static long __sbi_base_ecall(int fid)
-{
-       struct sbiret ret;
-
-       ret = sbi_ecall(SBI_EXT_BASE, fid, 0, 0, 0, 0, 0, 0);
-       if (!ret.error)
-               return ret.value;
-       else
-               return sbi_err_map_linux_errno(ret.error);
-}
-
 static inline long sbi_get_spec_version(void)
 {
        return __sbi_base_ecall(SBI_EXT_BASE_GET_SPEC_VERSION);
diff --git a/arch/riscv/kernel/sbi_ecall.c b/arch/riscv/kernel/sbi_ecall.c
new file mode 100644 (file)
index 0000000..24aabb4
--- /dev/null
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2024 Rivos Inc. */
+
+#include <asm/sbi.h>
+#define CREATE_TRACE_POINTS
+#include <asm/trace.h>
+
+long __sbi_base_ecall(int fid)
+{
+       struct sbiret ret;
+
+       ret = sbi_ecall(SBI_EXT_BASE, fid, 0, 0, 0, 0, 0, 0);
+       if (!ret.error)
+               return ret.value;
+       else
+               return sbi_err_map_linux_errno(ret.error);
+}
+EXPORT_SYMBOL(__sbi_base_ecall);
+
+struct sbiret __sbi_ecall(unsigned long arg0, unsigned long arg1,
+                         unsigned long arg2, unsigned long arg3,
+                         unsigned long arg4, unsigned long arg5,
+                         int fid, int ext)
+{
+       struct sbiret ret;
+
+       trace_sbi_call(ext, fid);
+
+       register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
+       register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
+       register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
+       register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
+       register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
+       register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
+       register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
+       register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
+       asm volatile ("ecall"
+                      : "+r" (a0), "+r" (a1)
+                      : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
+                      : "memory");
+       ret.error = a0;
+       ret.value = a1;
+
+       trace_sbi_return(ext, ret.error, ret.value);
+
+       return ret;
+}
+EXPORT_SYMBOL(__sbi_ecall);