[PATCH -fixes] riscv: Fix RISCV_ALTERNATIVE_EARLY

Alexandre Ghiti alexghiti at rivosinc.com
Wed Aug 28 06:32:15 PDT 2024


Hi Samuel,

On Wed, Aug 28, 2024 at 3:08 PM Samuel Holland
<samuel.holland at sifive.com> wrote:
>
> Hi Alex,
>
> On 2024-08-26 5:57 AM, Alexandre Ghiti wrote:
> > 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.
>
> Looking at the baseline disassembly from both LLVM 19 and GCC 13.2.0 with
> RISCV_ALTERNATIVE_EARLY + KASAN + TRACEPOINTS, all of the instrumentation in
> __sbi_ecall() itself is out of line and only executed when the tracepoint static
> branches are enabled. However, there is instrumentation in sbi_get_m*id() from
> the switch table inlined from sbi_err_map_linux_errno(), and some of those
> memory accesses are done unconditionally.
>
> This change will force sbi_err_map_linux_errno() to be out of line (unless LTO
> is enabled), so it also forces that particular bit of instrumentation to be
> executed only in the error path. But we could still crash in the error path. So
> I think sbi_err_map_linux_errno() needs to be moved to sbi_ecall.c as well.
>
> Alternatively, sbi_get_m*id() do not have any errors defined (and we don't
> really handle that possibility), so we could drop to the call to
> sbi_err_map_linux_errno() from __sbi_base_ecall().

Damn, I should have checked but I was sure it was a static inline in
sbi.h, which would be another solution. I prefer this solution, WDYT?

Thanks,

Alex

>
> Regards,
> Samuel
>
> > Fixes: 1745cfafebdf ("riscv: don't use global static vars to store alternative data")
> > Signed-off-by: Alexandre Ghiti <alexghiti at rivosinc.com>
> > ---
> >  arch/riscv/include/asm/sbi.h  |  2 ++
> >  arch/riscv/kernel/Makefile    |  6 ++++-
> >  arch/riscv/kernel/sbi.c       | 44 --------------------------------
> >  arch/riscv/kernel/sbi_ecall.c | 48 +++++++++++++++++++++++++++++++++++
> >  4 files changed, 55 insertions(+), 45 deletions(-)
> >  create mode 100644 arch/riscv/kernel/sbi_ecall.c
> >
> > diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
> > index 7cffd4ffecd0..5843a10b380e 100644
> > --- a/arch/riscv/include/asm/sbi.h
> > +++ b/arch/riscv/include/asm/sbi.h
> > @@ -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,
> > diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
> > index 06d407f1b30b..7f88cc4931f5 100644
> > --- a/arch/riscv/kernel/Makefile
> > +++ b/arch/riscv/kernel/Makefile
> > @@ -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
> > diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
> > index 837bdab2601b..ace9e2f59c41 100644
> > --- a/arch/riscv/kernel/sbi.c
> > +++ b/arch/riscv/kernel/sbi.c
> > @@ -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,36 +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) {
> > @@ -535,17 +502,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
> > index 000000000000..24aabb4fbde3
> > --- /dev/null
> > +++ b/arch/riscv/kernel/sbi_ecall.c
> > @@ -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);
>



More information about the linux-riscv mailing list