Re: [PATCH v2] riscv: Add support to no-FPU systems
On Fri, Aug 03, 2018 at 09:03:00PM -0700, Palmer Dabbelt wrote: > On Wed, 01 Aug 2018 11:23:43 PDT (-0700), Andrew Waterman wrote: > >On Wed, Aug 1, 2018 at 10:55 AM, Palmer Dabbelt wrote: > >>On Tue, 26 Jun 2018 21:22:26 PDT (-0700), alan...@andestech.com wrote: > >>> > >>>This patch adds an option, CONFIG_FPU, to enable/disable floating > >>>procedures. Also, some style issues are fixed. > >>> > >>>Signed-off-by: Alan Kao > >>>Cc: Greentime Hu > >>>Cc: Zong Li > >>>--- > >>> arch/riscv/Kconfig | 9 > >>> arch/riscv/Makefile| 19 +++ > >>> arch/riscv/include/asm/switch_to.h | 6 +++ > >>> arch/riscv/kernel/entry.S | 3 +- > >>> arch/riscv/kernel/process.c| 7 ++- > >>> arch/riscv/kernel/signal.c | 82 +- > >>> 6 files changed, 90 insertions(+), 36 deletions(-) > >>> > >>>diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig > >>>index 6debcc4afc72..6069597ba73f 100644 > >>>--- a/arch/riscv/Kconfig > >>>+++ b/arch/riscv/Kconfig > >>>@@ -232,6 +232,15 @@ config RISCV_BASE_PMU > >>> > >>> endmenu > >>> > >>>+config FPU > >>>+ bool "FPU support" > >>>+ default y > >>>+ help > >>>+ Say N here if you want to disable all floating-point related > >>>procedure > >>>+ in the kernel. > >>>+ > >>>+ If you don't know what to do here, say Y. > >>>+ > >>> endmenu > >> > >> > >>Sorry for letting this slide for a bit. While I'm not opposed to a solution > >>that requires a FPU Kconfig option, it'd be a bit better if we could detect > >>this at boot time. I think this should be possible because at one point > >>this actually worked and we could boot the same kernel on FPU and no-FPU > >>systems. > > > >I believe it would suffice to have start_thread set sstatus.FS to OFF > >for no-FPU systems (vs. INITIAL for systems with FPU). The ISA > >string in the devicetree should indicate whether F/D extensions are > >present. > > > >That said, it makes sense to me to additionally provide the Kconfig > >option. This would elide the sstatus.SD check for no-FPU systems, > >shaving a couple instructions off the context-switch path. It would > >also enable mimicking the behavior of a no-FPU system even when the > >FPU is present. > > That sounds like a good argument. Do you mind submitting a two-part patch > set, to: > > * Allow FPU kernels to detect and run correctly on non-FPU systems. You > should be able to detect these very early by writing to sstatus, or later > by looking at the device tree. > * Add a Kconfig option to disable the FPU entirely (which is pretty much > this patch). > > Thanks! > Thanks for the feedback from all of you. We will fix v3 according to Christph's suggestions, and append a new patch of the auto-detecting feature.
[PATCH v4 0/5] riscv: Add support to no-FPU systems
This patchset adds an option, CONFIG_FPU, to enable/disable floating- point procedures. Kernel's new behavior will be as follows: * with CONFIG_FPU=y All FPU codes are reserved. If no FPU is found during booting, a global flag will be set, and those functions will be bypassed with condition check to that flag. * with CONFIG_FPU=n No floating-point instructions in kernel and all related settings are excluded. Changes in v4: - Append a new patch to detect existence of FPU and followups. - Add SPDX header to newly created fpu.S. - Fix a build error, sorry for that. - Fix wording, style, etc. Changes in v3: - Refactor the whole patch into independent ones. Changes in v2: - Various code cleanups and style fixes. Alan Kao (5): Extract FPU context operations from entry.S Refactor FPU code in signal setup/return procedures Cleanup ISA string setting Allow to disable FPU support Auto-detect whether a FPU exists arch/riscv/Kconfig | 9 +++ arch/riscv/Makefile| 19 +++--- arch/riscv/include/asm/hwcap.h | 3 + arch/riscv/include/asm/switch_to.h | 21 ++ arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/cpufeature.c | 11 +++ arch/riscv/kernel/entry.S | 87 --- arch/riscv/kernel/fpu.S| 106 + arch/riscv/kernel/process.c| 4 +- arch/riscv/kernel/signal.c | 79 + 10 files changed, 214 insertions(+), 126 deletions(-) create mode 100644 arch/riscv/kernel/fpu.S -- 2.18.0
[PATCH v4 5/5] Auto-detect whether a FPU exists
We expect that a kernel with CONFIG_FPU=y can still support no-FPU machines. To do so, the kernel should first examine the existence of a FPU, then do nothing if a FPU does exist; otherwise, it should disable/bypass all FPU-related functions. In this patch, a new global variable, no_fpu, is created and determined when parsing the hardware capability from device tree during booting. This variable is used in those FPU-related functions. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/include/asm/hwcap.h | 3 +++ arch/riscv/include/asm/switch_to.h | 13 - arch/riscv/kernel/cpufeature.c | 11 +++ arch/riscv/kernel/signal.c | 6 ++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index 8a4ed7bbcbea..1b870086a869 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -33,5 +33,8 @@ enum { }; extern unsigned long elf_hwcap; +#ifdef CONFIG_FPU +extern bool no_fpu; +#endif #endif #endif diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index 093050b03543..7278e3eb7a70 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_FPU extern void __fstate_save(struct task_struct *save_to); @@ -30,6 +31,9 @@ static inline void __fstate_clean(struct pt_regs *regs) static inline void fstate_save(struct task_struct *task, struct pt_regs *regs) { + if (unlikely(no_fpu)) + return; + if ((regs->sstatus & SR_FS) == SR_FS_DIRTY) { __fstate_save(task); __fstate_clean(regs); @@ -39,6 +43,9 @@ static inline void fstate_save(struct task_struct *task, static inline void fstate_restore(struct task_struct *task, struct pt_regs *regs) { + if (unlikely(no_fpu)) + return; + if ((regs->sstatus & SR_FS) != SR_FS_OFF) { __fstate_restore(task); __fstate_clean(regs); @@ -50,13 +57,17 @@ static inline void __switch_to_aux(struct task_struct *prev, { struct pt_regs *regs; + if (unlikely(no_fpu)) + return; + regs = task_pt_regs(prev); if (unlikely(regs->sstatus & SR_SD)) fstate_save(prev, regs); fstate_restore(next, task_pt_regs(next)); } -#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) +#define DEFAULT_SSTATUS \ + ((unlikely(no_fpu)) ? (SR_SPIE | SR_FS_OFF) : (SR_SPIE | SR_FS_INITIAL)) #else #define fstate_save(task, regs) do { } while (0) diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 17011a870044..bc269c1e0b1a 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -22,6 +22,9 @@ #include unsigned long elf_hwcap __read_mostly; +#ifdef CONFIG_FPU +bool no_fpu __read_mostly; +#endif void riscv_fill_hwcap(void) { @@ -58,4 +61,12 @@ void riscv_fill_hwcap(void) elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; pr_info("elf_hwcap is 0x%lx", elf_hwcap); + +#ifdef CONFIG_FPU + no_fpu = 0; + if (!(elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))) { + pr_info("Bypass FPU code."); + no_fpu = 1; + } +#endif } diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 2450b824d799..9714e4fccb69 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -45,6 +45,9 @@ static long restore_fp_state(struct pt_regs *regs, struct __riscv_d_ext_state __user *state = &sc_fpregs->d; size_t i; + if (unlikely(no_fpu)) + return 0; + err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state)); if (unlikely(err)) return err; @@ -72,6 +75,9 @@ static long save_fp_state(struct pt_regs *regs, struct __riscv_d_ext_state __user *state = &sc_fpregs->d; size_t i; + if (unlikely(no_fpu)) + return 0; + fstate_save(current, regs); err = __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); if (unlikely(err)) -- 2.18.0
[PATCH v4 2/5] Refactor FPU code in signal setup/return procedures
FPU-related logic is separated from normal signal handling path in this patch. Kernel can easily be configured to exclude those procedures for no-FPU systems. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/kernel/signal.c | 68 +++--- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 718d0c984ef0..6a18b9819ead 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,45 +37,63 @@ struct rt_sigframe { struct ucontext uc; }; -static long restore_d_state(struct pt_regs *regs, - struct __riscv_d_ext_state __user *state) +static long restore_fp_state(struct pt_regs *regs, +union __riscv_fp_state *sc_fpregs) { long err; + struct __riscv_d_ext_state __user *state = &sc_fpregs->d; + size_t i; + err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state)); - if (likely(!err)) - fstate_restore(current, regs); + if (unlikely(err)) + return err; + + fstate_restore(current, regs); + + /* We support no other extension state at this time. */ + for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { + u32 value; + + err = __get_user(value, &sc_fpregs->q.reserved[i]); + if (unlikely(err)) + break; + if (value != 0) + return -EINVAL; + } + return err; } -static long save_d_state(struct pt_regs *regs, - struct __riscv_d_ext_state __user *state) +static long save_fp_state(struct pt_regs *regs, + union __riscv_fp_state *sc_fpregs) { + long err; + struct __riscv_d_ext_state __user *state = &sc_fpregs->d; + size_t i; + fstate_save(current, regs); - return __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); + err = __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); + if (unlikely(err)) + return err; + + /* We support no other extension state at this time. */ + for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { + err = __put_user(0, &sc_fpregs->q.reserved[i]); + if (unlikely(err)) + break; + } + + return err; } static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { long err; - size_t i; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); - if (unlikely(err)) - return err; /* Restore the floating-point state. */ - err = restore_d_state(regs, &sc->sc_fpregs.d); - if (unlikely(err)) - return err; - /* We support no other extension state at this time. */ - for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) { - u32 value; - err = __get_user(value, &sc->sc_fpregs.q.reserved[i]); - if (unlikely(err)) - break; - if (value != 0) - return -EINVAL; - } + err |= restore_fp_state(regs, &sc->sc_fpregs); return err; } @@ -124,14 +142,10 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, { struct sigcontext __user *sc = &frame->uc.uc_mcontext; long err; - size_t i; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); /* Save the floating-point state. */ - err |= save_d_state(regs, &sc->sc_fpregs.d); - /* We support no other extension state at this time. */ - for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) - err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]); + err |= save_fp_state(regs, &sc->sc_fpregs); return err; } -- 2.18.0
[PATCH v4 3/5] Cleanup ISA string setting
Just a side note: (Assume that atomic and compressed is on) Before this patch, assembler was always given the riscv64imafdc MARCH string because there are fld/fsd's in entry.S; compiler was always given riscv64imac because kernel doesn't need floating point code generation. After this, the MARCH string in AFLAGS and CFLAGS become the same. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/Makefile | 19 --- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 6d4a5f6c3f4f..e0fe6790624f 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -26,7 +26,6 @@ ifeq ($(CONFIG_ARCH_RV64I),y) KBUILD_CFLAGS += -mabi=lp64 KBUILD_AFLAGS += -mabi=lp64 - KBUILD_MARCH = rv64im LDFLAGS += -melf64lriscv else BITS := 32 @@ -34,22 +33,20 @@ else KBUILD_CFLAGS += -mabi=ilp32 KBUILD_AFLAGS += -mabi=ilp32 - KBUILD_MARCH = rv32im LDFLAGS += -melf32lriscv endif KBUILD_CFLAGS += -Wall -ifeq ($(CONFIG_RISCV_ISA_A),y) - KBUILD_ARCH_A = a -endif -ifeq ($(CONFIG_RISCV_ISA_C),y) - KBUILD_ARCH_C = c -endif - -KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) +# ISA string setting +riscv-march-$(CONFIG_ARCH_RV32I) := rv32im +riscv-march-$(CONFIG_ARCH_RV64I) := rv64im +riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a +riscv-march-y := $(riscv-march-y)fd +riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c +KBUILD_CFLAGS += -march=$(riscv-march-y) +KBUILD_AFLAGS += -march=$(riscv-march-y) -KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C) KBUILD_CFLAGS += -mno-save-restore KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET) -- 2.18.0
[PATCH v4 1/5] Extract FPU context operations from entry.S
We move __fstate_save and __fstate_restore to a new source file, fpu.S. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/entry.S | 87 -- arch/riscv/kernel/fpu.S| 106 + 3 files changed, 107 insertions(+), 87 deletions(-) create mode 100644 arch/riscv/kernel/fpu.S diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index e1274fc03af4..bd433efd915e 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -13,6 +13,7 @@ extra-y += vmlinux.lds obj-y += cpu.o obj-y += cpufeature.o obj-y += entry.o +obj-y += fpu.o obj-y += irq.o obj-y += process.o obj-y += ptrace.o diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 9aaf6c986771..edcd5920ee4e 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -357,93 +357,6 @@ ENTRY(__switch_to) ret ENDPROC(__switch_to) -ENTRY(__fstate_save) - li a2, TASK_THREAD_F0 - add a0, a0, a2 - li t1, SR_FS - csrs sstatus, t1 - frcsr t0 - fsd f0, TASK_THREAD_F0_F0(a0) - fsd f1, TASK_THREAD_F1_F0(a0) - fsd f2, TASK_THREAD_F2_F0(a0) - fsd f3, TASK_THREAD_F3_F0(a0) - fsd f4, TASK_THREAD_F4_F0(a0) - fsd f5, TASK_THREAD_F5_F0(a0) - fsd f6, TASK_THREAD_F6_F0(a0) - fsd f7, TASK_THREAD_F7_F0(a0) - fsd f8, TASK_THREAD_F8_F0(a0) - fsd f9, TASK_THREAD_F9_F0(a0) - fsd f10, TASK_THREAD_F10_F0(a0) - fsd f11, TASK_THREAD_F11_F0(a0) - fsd f12, TASK_THREAD_F12_F0(a0) - fsd f13, TASK_THREAD_F13_F0(a0) - fsd f14, TASK_THREAD_F14_F0(a0) - fsd f15, TASK_THREAD_F15_F0(a0) - fsd f16, TASK_THREAD_F16_F0(a0) - fsd f17, TASK_THREAD_F17_F0(a0) - fsd f18, TASK_THREAD_F18_F0(a0) - fsd f19, TASK_THREAD_F19_F0(a0) - fsd f20, TASK_THREAD_F20_F0(a0) - fsd f21, TASK_THREAD_F21_F0(a0) - fsd f22, TASK_THREAD_F22_F0(a0) - fsd f23, TASK_THREAD_F23_F0(a0) - fsd f24, TASK_THREAD_F24_F0(a0) - fsd f25, TASK_THREAD_F25_F0(a0) - fsd f26, TASK_THREAD_F26_F0(a0) - fsd f27, TASK_THREAD_F27_F0(a0) - fsd f28, TASK_THREAD_F28_F0(a0) - fsd f29, TASK_THREAD_F29_F0(a0) - fsd f30, TASK_THREAD_F30_F0(a0) - fsd f31, TASK_THREAD_F31_F0(a0) - sw t0, TASK_THREAD_FCSR_F0(a0) - csrc sstatus, t1 - ret -ENDPROC(__fstate_save) - -ENTRY(__fstate_restore) - li a2, TASK_THREAD_F0 - add a0, a0, a2 - li t1, SR_FS - lw t0, TASK_THREAD_FCSR_F0(a0) - csrs sstatus, t1 - fld f0, TASK_THREAD_F0_F0(a0) - fld f1, TASK_THREAD_F1_F0(a0) - fld f2, TASK_THREAD_F2_F0(a0) - fld f3, TASK_THREAD_F3_F0(a0) - fld f4, TASK_THREAD_F4_F0(a0) - fld f5, TASK_THREAD_F5_F0(a0) - fld f6, TASK_THREAD_F6_F0(a0) - fld f7, TASK_THREAD_F7_F0(a0) - fld f8, TASK_THREAD_F8_F0(a0) - fld f9, TASK_THREAD_F9_F0(a0) - fld f10, TASK_THREAD_F10_F0(a0) - fld f11, TASK_THREAD_F11_F0(a0) - fld f12, TASK_THREAD_F12_F0(a0) - fld f13, TASK_THREAD_F13_F0(a0) - fld f14, TASK_THREAD_F14_F0(a0) - fld f15, TASK_THREAD_F15_F0(a0) - fld f16, TASK_THREAD_F16_F0(a0) - fld f17, TASK_THREAD_F17_F0(a0) - fld f18, TASK_THREAD_F18_F0(a0) - fld f19, TASK_THREAD_F19_F0(a0) - fld f20, TASK_THREAD_F20_F0(a0) - fld f21, TASK_THREAD_F21_F0(a0) - fld f22, TASK_THREAD_F22_F0(a0) - fld f23, TASK_THREAD_F23_F0(a0) - fld f24, TASK_THREAD_F24_F0(a0) - fld f25, TASK_THREAD_F25_F0(a0) - fld f26, TASK_THREAD_F26_F0(a0) - fld f27, TASK_THREAD_F27_F0(a0) - fld f28, TASK_THREAD_F28_F0(a0) - fld f29, TASK_THREAD_F29_F0(a0) - fld f30, TASK_THREAD_F30_F0(a0) - fld f31, TASK_THREAD_F31_F0(a0) - fscsr t0 - csrc sstatus, t1 - ret -ENDPROC(__fstate_restore) - - .section ".rodata" /* Exception vector table */ ENTRY(excp_vect_table) diff --git a/arch/riscv/kernel/fpu.S b/arch/riscv/kernel/fpu.S new file mode 100644 index ..1defb0618aff --- /dev/null +++ b/arch/riscv/kernel/fpu.S @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2012 Regents of the University of California + * Copyright (C) 2017 SiFive + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +
[PATCH v4 4/5] Allow to disable FPU support
FPU codes have been separated from common part in previous patches. This patch add the CONFIG_FPU option and some stubs, so that a no-FPU configuration is allowed. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/Kconfig | 9 + arch/riscv/include/asm/switch_to.h | 10 ++ arch/riscv/kernel/Makefile | 2 +- arch/riscv/kernel/process.c| 4 +++- arch/riscv/kernel/signal.c | 5 + 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 6debcc4afc72..6069597ba73f 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -232,6 +232,15 @@ config RISCV_BASE_PMU endmenu +config FPU + bool "FPU support" + default y + help + Say N here if you want to disable all floating-point related procedure + in the kernel. + + If you don't know what to do here, say Y. + endmenu menu "Kernel type" diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index dd6b05bff75b..093050b03543 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -18,6 +18,7 @@ #include #include +#ifdef CONFIG_FPU extern void __fstate_save(struct task_struct *save_to); extern void __fstate_restore(struct task_struct *restore_from); @@ -55,6 +56,15 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_restore(next, task_pt_regs(next)); } +#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) + +#else +#define fstate_save(task, regs) do { } while (0) +#define fstate_restore(task, regs) do { } while (0) +#define __switch_to_aux(__prev, __next) do { } while (0) +#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_OFF) +#endif + extern struct task_struct *__switch_to(struct task_struct *, struct task_struct *); diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index bd433efd915e..f13f7f276639 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -13,7 +13,6 @@ extra-y += vmlinux.lds obj-y += cpu.o obj-y += cpufeature.o obj-y += entry.o -obj-y += fpu.o obj-y += irq.o obj-y += process.o obj-y += ptrace.o @@ -32,6 +31,7 @@ obj-y += vdso/ CFLAGS_setup.o := -mcmodel=medany +obj-$(CONFIG_FPU) += fpu.o obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index cb209139ba53..3820d89e2db9 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -83,7 +83,7 @@ void show_regs(struct pt_regs *regs) void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - regs->sstatus = SR_SPIE /* User mode, irqs on */ | SR_FS_INITIAL; + regs->sstatus = DEFAULT_SSTATUS; regs->sepc = pc; regs->sp = sp; set_fs(USER_DS); @@ -91,12 +91,14 @@ void start_thread(struct pt_regs *regs, unsigned long pc, void flush_thread(void) { +#ifdef CONFIG_FPU /* * Reset FPU context * frm: round to nearest, ties to even (IEEE default) * fflags: accrued exceptions cleared */ memset(¤t->thread.fstate, 0, sizeof(current->thread.fstate)); +#endif } int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 6a18b9819ead..2450b824d799 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,6 +37,7 @@ struct rt_sigframe { struct ucontext uc; }; +#ifdef CONFIG_FPU static long restore_fp_state(struct pt_regs *regs, union __riscv_fp_state *sc_fpregs) { @@ -85,6 +86,10 @@ static long save_fp_state(struct pt_regs *regs, return err; } +#else +#define save_fp_state(task, regs) (0) +#define restore_fp_state(task, regs) (0) +#endif static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) -- 2.18.0
[PATCH] riscv: Add support to no-FPU systems
This patch adds an option, CONFIG_FPU, so that we can enable/disable floating procedures in kernel. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Zong Li --- arch/riscv/Kconfig | 4 arch/riscv/Makefile| 4 arch/riscv/include/asm/switch_to.h | 4 arch/riscv/kernel/entry.S | 3 ++- arch/riscv/kernel/process.c| 6 ++ arch/riscv/kernel/signal.c | 6 ++ 6 files changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 6debcc4afc72..429d0bf777c9 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -232,6 +232,10 @@ config RISCV_BASE_PMU endmenu +config FPU + bool "FPU support" + default y + endmenu menu "Kernel type" diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 76e958a5414a..2719e768c4dc 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -47,7 +47,11 @@ ifeq ($(CONFIG_RISCV_ISA_C),y) KBUILD_ARCH_C = c endif +ifeq ($(CONFIG_FPU),y) KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) +else +KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C) +endif KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C) KBUILD_CFLAGS += -mno-save-restore diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index dd6b05bff75b..da0327a74466 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -18,6 +18,7 @@ #include #include +#ifdef CONFIG_FPU extern void __fstate_save(struct task_struct *save_to); extern void __fstate_restore(struct task_struct *restore_from); @@ -54,6 +55,9 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_save(prev, regs); fstate_restore(next, task_pt_regs(next)); } +#else +#define __switch_to_aux(__prev, __next) +#endif extern struct task_struct *__switch_to(struct task_struct *, struct task_struct *); diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 9aaf6c986771..89867c9aa4f5 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -357,6 +357,7 @@ ENTRY(__switch_to) ret ENDPROC(__switch_to) +#ifdef CONFIG_FPU ENTRY(__fstate_save) li a2, TASK_THREAD_F0 add a0, a0, a2 @@ -442,7 +443,7 @@ ENTRY(__fstate_restore) csrc sstatus, t1 ret ENDPROC(__fstate_restore) - +#endif .section ".rodata" /* Exception vector table */ diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index cb209139ba53..a817046e478a 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -83,7 +83,11 @@ void show_regs(struct pt_regs *regs) void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { +#ifdef CONFIG_FPU regs->sstatus = SR_SPIE /* User mode, irqs on */ | SR_FS_INITIAL; +#else + regs->sstatus = SR_SPIE | SR_FS_OFF; +#endif regs->sepc = pc; regs->sp = sp; set_fs(USER_DS); @@ -101,7 +105,9 @@ void flush_thread(void) int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { +#ifdef CONFIG_FPU fstate_save(src, task_pt_regs(src)); +#endif *dst = *src; return 0; } diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 718d0c984ef0..0f659c9ef465 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,6 +37,7 @@ struct rt_sigframe { struct ucontext uc; }; +#ifdef CONFIG_FPU static long restore_d_state(struct pt_regs *regs, struct __riscv_d_ext_state __user *state) { @@ -53,6 +54,7 @@ static long save_d_state(struct pt_regs *regs, fstate_save(current, regs); return __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); } +#endif static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) @@ -63,6 +65,7 @@ static long restore_sigcontext(struct pt_regs *regs, err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); if (unlikely(err)) return err; +#ifdef CONFIG_FPU /* Restore the floating-point state. */ err = restore_d_state(regs, &sc->sc_fpregs.d); if (unlikely(err)) @@ -76,6 +79,7 @@ static long restore_sigcontext(struct pt_regs *regs, if (value != 0) return -EINVAL; } +#endif return err; } @@ -127,11 +131,13 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, size_t i; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); +#ifdef CONFIG_FPU /* Save the floating-point state. */ err |= save_d_state(regs, &sc->sc_fpregs.d);
Re: [PATCH] riscv: Add support to no-FPU systems
On Wed, Jun 20, 2018 at 11:39:38PM -0700, Christoph Hellwig wrote: > > +ifeq ($(CONFIG_FPU),y) > > KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) > > +else > > +KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C) > > +endif > > Can we refactor that KBUILD_ARCH code into something like > > riscv-march-y := > riscv-march-$(CONFIG_ARCH_RV32I) += rv32im > riscv-march-$(CONFIG_ARCH_RV64I) += rv64im > riscv-march-$(CONFIG_RISCV_ISA_A) += a > riscv-march-$(CONFIG_FPU) += fd > riscv-march-$(CONFIG_RISCV_ISA_C) += c > > KBUILD_CFLAGS += -march=$(riscv-march-y) > That's neat, sure. > > +#ifdef CONFIG_FPU > > regs->sstatus = SR_SPIE /* User mode, irqs on */ | SR_FS_INITIAL; > > +#else > > + regs->sstatus = SR_SPIE | SR_FS_OFF; > > +#endif > > Having the comment in one branch, but not the other is odd. I'd be > tempted to just remove t entirely, but if not it should be move up > or duplicated. > I'll move that comment up. > > int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) > > { > > +#ifdef CONFIG_FPU > > fstate_save(src, task_pt_regs(src)); > > +#endif > > Please provide a !CONFIG_FPU stub for fstate_save, please. > > > } It's OK to do this to fstate_save/restore, and > > +#endif > > > > static long restore_sigcontext(struct pt_regs *regs, > > struct sigcontext __user *sc) > > @@ -63,6 +65,7 @@ static long restore_sigcontext(struct pt_regs *regs, > > err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); > > if (unlikely(err)) > > return err; > > +#ifdef CONFIG_FPU > > /* Restore the floating-point state. */ > > err = restore_d_state(regs, &sc->sc_fpregs.d); > > if (unlikely(err)) > > @@ -76,6 +79,7 @@ static long restore_sigcontext(struct pt_regs *regs, > > if (value != 0) > > return -EINVAL; > > } > > +#endif > > Same here. > it's also OK to do so to restore_d_state/save_d_state. But what to do with the following __get_user/__put_user calls? Can I rename existing restore_d_state to __restore_d_state, and create a new function restore_d_state which includes the original restore_d_state/__get_user pair, and the same to save_d_state? > > @@ -127,11 +131,13 @@ static long setup_sigcontext(struct rt_sigframe > > __user *frame, > > size_t i; > > /* sc_regs is structured the same as the start of pt_regs */ > > err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); > > +#ifdef CONFIG_FPU > > /* Save the floating-point state. */ > > err |= save_d_state(regs, &sc->sc_fpregs.d); > > /* We support no other extension state at this time. */ > > for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) > > err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]); > > +#endif > > Same here. > Thanks, Alan
[PATCH 1/5] Extract FPU context operations from entry.S
We move __fstate_save and __fstate_restore to a new source file, fpu.S. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/entry.S | 87 -- arch/riscv/kernel/fpu.S| 106 + 3 files changed, 107 insertions(+), 87 deletions(-) create mode 100644 arch/riscv/kernel/fpu.S diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index e1274fc03af4..bd433efd915e 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -13,6 +13,7 @@ extra-y += vmlinux.lds obj-y += cpu.o obj-y += cpufeature.o obj-y += entry.o +obj-y += fpu.o obj-y += irq.o obj-y += process.o obj-y += ptrace.o diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index fa2c08e3c05e..59c02e2bf739 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -357,93 +357,6 @@ ENTRY(__switch_to) ret ENDPROC(__switch_to) -ENTRY(__fstate_save) - li a2, TASK_THREAD_F0 - add a0, a0, a2 - li t1, SR_FS - csrs sstatus, t1 - frcsr t0 - fsd f0, TASK_THREAD_F0_F0(a0) - fsd f1, TASK_THREAD_F1_F0(a0) - fsd f2, TASK_THREAD_F2_F0(a0) - fsd f3, TASK_THREAD_F3_F0(a0) - fsd f4, TASK_THREAD_F4_F0(a0) - fsd f5, TASK_THREAD_F5_F0(a0) - fsd f6, TASK_THREAD_F6_F0(a0) - fsd f7, TASK_THREAD_F7_F0(a0) - fsd f8, TASK_THREAD_F8_F0(a0) - fsd f9, TASK_THREAD_F9_F0(a0) - fsd f10, TASK_THREAD_F10_F0(a0) - fsd f11, TASK_THREAD_F11_F0(a0) - fsd f12, TASK_THREAD_F12_F0(a0) - fsd f13, TASK_THREAD_F13_F0(a0) - fsd f14, TASK_THREAD_F14_F0(a0) - fsd f15, TASK_THREAD_F15_F0(a0) - fsd f16, TASK_THREAD_F16_F0(a0) - fsd f17, TASK_THREAD_F17_F0(a0) - fsd f18, TASK_THREAD_F18_F0(a0) - fsd f19, TASK_THREAD_F19_F0(a0) - fsd f20, TASK_THREAD_F20_F0(a0) - fsd f21, TASK_THREAD_F21_F0(a0) - fsd f22, TASK_THREAD_F22_F0(a0) - fsd f23, TASK_THREAD_F23_F0(a0) - fsd f24, TASK_THREAD_F24_F0(a0) - fsd f25, TASK_THREAD_F25_F0(a0) - fsd f26, TASK_THREAD_F26_F0(a0) - fsd f27, TASK_THREAD_F27_F0(a0) - fsd f28, TASK_THREAD_F28_F0(a0) - fsd f29, TASK_THREAD_F29_F0(a0) - fsd f30, TASK_THREAD_F30_F0(a0) - fsd f31, TASK_THREAD_F31_F0(a0) - sw t0, TASK_THREAD_FCSR_F0(a0) - csrc sstatus, t1 - ret -ENDPROC(__fstate_save) - -ENTRY(__fstate_restore) - li a2, TASK_THREAD_F0 - add a0, a0, a2 - li t1, SR_FS - lw t0, TASK_THREAD_FCSR_F0(a0) - csrs sstatus, t1 - fld f0, TASK_THREAD_F0_F0(a0) - fld f1, TASK_THREAD_F1_F0(a0) - fld f2, TASK_THREAD_F2_F0(a0) - fld f3, TASK_THREAD_F3_F0(a0) - fld f4, TASK_THREAD_F4_F0(a0) - fld f5, TASK_THREAD_F5_F0(a0) - fld f6, TASK_THREAD_F6_F0(a0) - fld f7, TASK_THREAD_F7_F0(a0) - fld f8, TASK_THREAD_F8_F0(a0) - fld f9, TASK_THREAD_F9_F0(a0) - fld f10, TASK_THREAD_F10_F0(a0) - fld f11, TASK_THREAD_F11_F0(a0) - fld f12, TASK_THREAD_F12_F0(a0) - fld f13, TASK_THREAD_F13_F0(a0) - fld f14, TASK_THREAD_F14_F0(a0) - fld f15, TASK_THREAD_F15_F0(a0) - fld f16, TASK_THREAD_F16_F0(a0) - fld f17, TASK_THREAD_F17_F0(a0) - fld f18, TASK_THREAD_F18_F0(a0) - fld f19, TASK_THREAD_F19_F0(a0) - fld f20, TASK_THREAD_F20_F0(a0) - fld f21, TASK_THREAD_F21_F0(a0) - fld f22, TASK_THREAD_F22_F0(a0) - fld f23, TASK_THREAD_F23_F0(a0) - fld f24, TASK_THREAD_F24_F0(a0) - fld f25, TASK_THREAD_F25_F0(a0) - fld f26, TASK_THREAD_F26_F0(a0) - fld f27, TASK_THREAD_F27_F0(a0) - fld f28, TASK_THREAD_F28_F0(a0) - fld f29, TASK_THREAD_F29_F0(a0) - fld f30, TASK_THREAD_F30_F0(a0) - fld f31, TASK_THREAD_F31_F0(a0) - fscsr t0 - csrc sstatus, t1 - ret -ENDPROC(__fstate_restore) - - .section ".rodata" /* Exception vector table */ ENTRY(excp_vect_table) diff --git a/arch/riscv/kernel/fpu.S b/arch/riscv/kernel/fpu.S new file mode 100644 index ..1defb0618aff --- /dev/null +++ b/arch/riscv/kernel/fpu.S @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2012 Regents of the University of California + * Copyright (C) 2017 SiFive + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +
[PATCH 3/5] Cleanup ISA string setting
This patch cleanup the MARCH string passing to both compiler and assembler. Note that the CFLAGS should not contain "fd" before we have mechnisms like kernel_fpu_begin/end in other architectures. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/Makefile | 19 --- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 1f536a7784aa..33bd3b4dd926 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -29,7 +29,6 @@ ifeq ($(CONFIG_ARCH_RV64I),y) KBUILD_CFLAGS += $(call cc-ifversion, -ge, 0500, -DCONFIG_ARCH_SUPPORTS_INT128) - KBUILD_MARCH = rv64im LDFLAGS += -melf64lriscv else BITS := 32 @@ -37,22 +36,20 @@ else KBUILD_CFLAGS += -mabi=ilp32 KBUILD_AFLAGS += -mabi=ilp32 - KBUILD_MARCH = rv32im LDFLAGS += -melf32lriscv endif KBUILD_CFLAGS += -Wall -ifeq ($(CONFIG_RISCV_ISA_A),y) - KBUILD_ARCH_A = a -endif -ifeq ($(CONFIG_RISCV_ISA_C),y) - KBUILD_ARCH_C = c -endif - -KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) +# ISA string setting +riscv-march-$(CONFIG_ARCH_RV32I) := rv32im +riscv-march-$(CONFIG_ARCH_RV64I) := rv64im +riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a +riscv-march-y := fd +riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c +KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y)) +KBUILD_AFLAGS += -march=$(riscv-march-y) -KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C) KBUILD_CFLAGS += -mno-save-restore KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET) -- 2.18.0
[PATCH 5/5] Auto-detect whether a FPU exists
We expect that a kernel with CONFIG_FPU=y can still support no-FPU machines. To do so, the kernel should first examine the existence of a FPU, then do nothing if a FPU does exist; otherwise, it should disable/bypass all FPU-related functions. In this patch, a new global variable, has_fpu, is created and determined when parsing the hardware capability from device tree during booting. This variable is used in those FPU-related functions. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/include/asm/switch_to.h | 8 arch/riscv/kernel/cpufeature.c | 8 arch/riscv/kernel/process.c| 4 +++- arch/riscv/kernel/signal.c | 6 -- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index 093050b03543..733559083f24 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -56,13 +56,12 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_restore(next, task_pt_regs(next)); } -#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) - +extern bool has_fpu; #else +#define has_fpu false #define fstate_save(task, regs) do { } while (0) #define fstate_restore(task, regs) do { } while (0) #define __switch_to_aux(__prev, __next) do { } while (0) -#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_OFF) #endif extern struct task_struct *__switch_to(struct task_struct *, @@ -72,7 +71,8 @@ extern struct task_struct *__switch_to(struct task_struct *, do { \ struct task_struct *__prev = (prev);\ struct task_struct *__next = (next);\ - __switch_to_aux(__prev, __next);\ + if (has_fpu)\ + __switch_to_aux(__prev, __next);\ ((last) = __switch_to(__prev, __next)); \ } while (0) diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 17011a870044..46942e635266 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -22,6 +22,9 @@ #include unsigned long elf_hwcap __read_mostly; +#ifdef CONFIG_FPU +bool has_fpu __read_mostly; +#endif void riscv_fill_hwcap(void) { @@ -58,4 +61,9 @@ void riscv_fill_hwcap(void) elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; pr_info("elf_hwcap is 0x%lx", elf_hwcap); + +#ifdef CONFIG_FPU + if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)) + has_fpu = true; +#endif } diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 07d515655aa9..bef19993ea92 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -76,7 +76,9 @@ void show_regs(struct pt_regs *regs) void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - regs->sstatus = DEFAULT_SSTATUS; + regs->sstatus = SR_SPIE; + if (has_fpu) + regs->sstatus |= SR_FS_INITIAL; regs->sepc = pc; regs->sp = sp; set_fs(USER_DS); diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 2450b824d799..f9b5e7e352ef 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -98,7 +98,8 @@ static long restore_sigcontext(struct pt_regs *regs, /* sc_regs is structured the same as the start of pt_regs */ err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); /* Restore the floating-point state. */ - err |= restore_fp_state(regs, &sc->sc_fpregs); + if (has_fpu) + err |= restore_fp_state(regs, &sc->sc_fpregs); return err; } @@ -150,7 +151,8 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); /* Save the floating-point state. */ - err |= save_fp_state(regs, &sc->sc_fpregs); + if (has_fpu) + err |= save_fp_state(regs, &sc->sc_fpregs); return err; } -- 2.18.0
[PATCH 4/5] Allow to disable FPU support
FPU codes have been separated from common part in previous patches. This patch add the CONFIG_FPU option and some stubs, so that a no-FPU configuration is allowed. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/Kconfig | 9 + arch/riscv/Makefile| 2 +- arch/riscv/include/asm/switch_to.h | 10 ++ arch/riscv/kernel/Makefile | 2 +- arch/riscv/kernel/process.c| 4 +++- arch/riscv/kernel/signal.c | 5 + 6 files changed, 29 insertions(+), 3 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 4764fdeb4f1f..a29c9c3a3c5d 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -208,6 +208,15 @@ config RISCV_BASE_PMU endmenu +config FPU + bool "FPU support" + default y + help + Say N here if you want to disable all floating-point related procedure + in the kernel. + + If you don't know what to do here, say Y. + endmenu menu "Kernel type" diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 33bd3b4dd926..74dd2ce6110e 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -45,7 +45,7 @@ KBUILD_CFLAGS += -Wall riscv-march-$(CONFIG_ARCH_RV32I) := rv32im riscv-march-$(CONFIG_ARCH_RV64I) := rv64im riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a -riscv-march-y := fd +riscv-march-$(CONFIG_FPU) := fd riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y)) KBUILD_AFLAGS += -march=$(riscv-march-y) diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index dd6b05bff75b..093050b03543 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -18,6 +18,7 @@ #include #include +#ifdef CONFIG_FPU extern void __fstate_save(struct task_struct *save_to); extern void __fstate_restore(struct task_struct *restore_from); @@ -55,6 +56,15 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_restore(next, task_pt_regs(next)); } +#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) + +#else +#define fstate_save(task, regs) do { } while (0) +#define fstate_restore(task, regs) do { } while (0) +#define __switch_to_aux(__prev, __next) do { } while (0) +#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_OFF) +#endif + extern struct task_struct *__switch_to(struct task_struct *, struct task_struct *); diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index bd433efd915e..f13f7f276639 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -13,7 +13,6 @@ extra-y += vmlinux.lds obj-y += cpu.o obj-y += cpufeature.o obj-y += entry.o -obj-y += fpu.o obj-y += irq.o obj-y += process.o obj-y += ptrace.o @@ -32,6 +31,7 @@ obj-y += vdso/ CFLAGS_setup.o := -mcmodel=medany +obj-$(CONFIG_FPU) += fpu.o obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index d7c6ca7c95ae..07d515655aa9 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -76,7 +76,7 @@ void show_regs(struct pt_regs *regs) void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - regs->sstatus = SR_SPIE /* User mode, irqs on */ | SR_FS_INITIAL; + regs->sstatus = DEFAULT_SSTATUS; regs->sepc = pc; regs->sp = sp; set_fs(USER_DS); @@ -84,12 +84,14 @@ void start_thread(struct pt_regs *regs, unsigned long pc, void flush_thread(void) { +#ifdef CONFIG_FPU /* * Reset FPU context * frm: round to nearest, ties to even (IEEE default) * fflags: accrued exceptions cleared */ memset(¤t->thread.fstate, 0, sizeof(current->thread.fstate)); +#endif } int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 6a18b9819ead..2450b824d799 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,6 +37,7 @@ struct rt_sigframe { struct ucontext uc; }; +#ifdef CONFIG_FPU static long restore_fp_state(struct pt_regs *regs, union __riscv_fp_state *sc_fpregs) { @@ -85,6 +86,10 @@ static long save_fp_state(struct pt_regs *regs, return err; } +#else +#define save_fp_state(task, regs) (0) +#define restore_fp_state(task, regs) (0) +#endif static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) -- 2.18.0
[PATCH v7 0/5] riscv: Add support to no-FPU systems
This patchset adds an option, CONFIG_FPU, to enable/disable floating- point procedures. Kernel's new behavior will be as follows: * with CONFIG_FPU=y All FPU codes are reserved. If no FPU is found during booting, a global flag will be set, and those functions will be bypassed with condition check to that flag. * with CONFIG_FPU=n No floating-point instructions in kernel and all related settings are excluded. Changes in v7: - Remove "fd" attribute from KBUILD_CFLAGS. Changes in v6 (PATCH 0005 only): - Make the flag checking neater. Changes in v5: - Invert the polarity of checking flag from no_fpu to has_fpu. Changes in v4: - Append a new patch to detect existence of FPU and followups. - Add SPDX header to newly created fpu.S. - Fix a build error, sorry for that. - Fix wording, style, etc. Changes in v3: - Refactor the whole patch into independent ones. Changes in v2: - Various code cleanups and style fixes. Alan Kao (5): Extract FPU context operations from entry.S Refactor FPU code in signal setup/return procedures Cleanup ISA string setting Allow to disable FPU support Auto-detect whether a FPU exists arch/riscv/Kconfig | 9 +++ arch/riscv/Makefile| 19 +++--- arch/riscv/include/asm/switch_to.h | 12 +++- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/cpufeature.c | 8 +++ arch/riscv/kernel/entry.S | 87 --- arch/riscv/kernel/fpu.S| 106 + arch/riscv/kernel/process.c| 6 +- arch/riscv/kernel/signal.c | 75 9 files changed, 196 insertions(+), 127 deletions(-) create mode 100644 arch/riscv/kernel/fpu.S -- 2.18.0
[PATCH 2/5] Refactor FPU code in signal setup/return procedures
FPU-related logic is separated from normal signal handling path in this patch. Kernel can easily be configured to exclude those procedures for no-FPU systems. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/kernel/signal.c | 68 +++--- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 718d0c984ef0..6a18b9819ead 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,45 +37,63 @@ struct rt_sigframe { struct ucontext uc; }; -static long restore_d_state(struct pt_regs *regs, - struct __riscv_d_ext_state __user *state) +static long restore_fp_state(struct pt_regs *regs, +union __riscv_fp_state *sc_fpregs) { long err; + struct __riscv_d_ext_state __user *state = &sc_fpregs->d; + size_t i; + err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state)); - if (likely(!err)) - fstate_restore(current, regs); + if (unlikely(err)) + return err; + + fstate_restore(current, regs); + + /* We support no other extension state at this time. */ + for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { + u32 value; + + err = __get_user(value, &sc_fpregs->q.reserved[i]); + if (unlikely(err)) + break; + if (value != 0) + return -EINVAL; + } + return err; } -static long save_d_state(struct pt_regs *regs, - struct __riscv_d_ext_state __user *state) +static long save_fp_state(struct pt_regs *regs, + union __riscv_fp_state *sc_fpregs) { + long err; + struct __riscv_d_ext_state __user *state = &sc_fpregs->d; + size_t i; + fstate_save(current, regs); - return __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); + err = __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); + if (unlikely(err)) + return err; + + /* We support no other extension state at this time. */ + for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { + err = __put_user(0, &sc_fpregs->q.reserved[i]); + if (unlikely(err)) + break; + } + + return err; } static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { long err; - size_t i; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); - if (unlikely(err)) - return err; /* Restore the floating-point state. */ - err = restore_d_state(regs, &sc->sc_fpregs.d); - if (unlikely(err)) - return err; - /* We support no other extension state at this time. */ - for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) { - u32 value; - err = __get_user(value, &sc->sc_fpregs.q.reserved[i]); - if (unlikely(err)) - break; - if (value != 0) - return -EINVAL; - } + err |= restore_fp_state(regs, &sc->sc_fpregs); return err; } @@ -124,14 +142,10 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, { struct sigcontext __user *sc = &frame->uc.uc_mcontext; long err; - size_t i; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); /* Save the floating-point state. */ - err |= save_d_state(regs, &sc->sc_fpregs.d); - /* We support no other extension state at this time. */ - for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) - err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]); + err |= save_fp_state(regs, &sc->sc_fpregs); return err; } -- 2.18.0
Re: [PATCH] RISC-V: Mask out the F extension on systems without D
Hi Palmer, On Mon, Aug 27, 2018 at 03:03:52PM -0700, Palmer Dabbelt wrote: > The RISC-V Linux port doesn't support systems that have the F extension > but don't have the D extension -- we actually don't support systems > without D either, but Alan's patch set is rectifying that soon. For now > I think we can leave this in a semi-broken state and just wait for > Alan's patch set to get merged for proper non-FPU support -- the patch > set is starting to look good, so doing something in-between doesn't seem > like it's worth the work. > > I don't think it's worth fretting about support for systems with F but > not D for now: our glibc ABIs are IMAC and IMAFDC so they probably won't > end up being popular. We can always extend this in the future. > > CC: Alan Kao > Signed-off-by: Palmer Dabbelt > --- > arch/riscv/kernel/cpufeature.c | 7 +++ > 1 file changed, 7 insertions(+) > > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c > index 17011a870044..652d102ffa06 100644 > --- a/arch/riscv/kernel/cpufeature.c > +++ b/arch/riscv/kernel/cpufeature.c > @@ -57,5 +57,12 @@ void riscv_fill_hwcap(void) > for (i = 0; i < strlen(isa); ++i) > elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; > > + /* We don't support systems with F but without D, so mask those out > + * here. */ > + if ((elf_hwcap & COMPAT_HWCAP_ISA_F) && !(elf_hwcap & > COMPAT_HWCAP_ISA_D)) { > + pr_info("This kernel does not support systems with F but not > D"); > + elf_hwcap &= ~COMPAT_HWCAP_ISA_F; > + } > + The commit message does address the problem and this patch does provide checks and helpful information to users, but I wonder if we really need this patch, for two reasons: * Just as you mentioned, current glibc ABI does not support such a thing as IMAFC, so probably no one has had trouble with this. To be honest, I suppose that anybody (RISC-V enthusiasts or vendors) who really need F-only support in kernel should get themself involved in the development by sending patches to improve. * There are corner cases to let a F-only machine to pass the check in this patch. For instance, a vendor decides to name her extension ISA as doom, and supports single-precision FP only, so her ISA string would be IMAFCXdoom. The variable elf_hwcap is calculated at the loop in line 57,58, the 'd' from Xdoom would bypass the check, while the underlying machine does not support double-precision FP. > pr_info("elf_hwcap is 0x%lx", elf_hwcap); > } > -- > 2.16.4 > I don't know if the reasons make sense to you, but anyway that's all I would like to say about this patch. Alan
[PATCH v5 4/5] Allow to disable FPU support
FPU codes have been separated from common part in previous patches. This patch add the CONFIG_FPU option and some stubs, so that a no-FPU configuration is allowed. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/Kconfig | 9 + arch/riscv/include/asm/switch_to.h | 10 ++ arch/riscv/kernel/Makefile | 2 +- arch/riscv/kernel/process.c| 4 +++- arch/riscv/kernel/signal.c | 5 + 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 6debcc4afc72..6069597ba73f 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -232,6 +232,15 @@ config RISCV_BASE_PMU endmenu +config FPU + bool "FPU support" + default y + help + Say N here if you want to disable all floating-point related procedure + in the kernel. + + If you don't know what to do here, say Y. + endmenu menu "Kernel type" diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index dd6b05bff75b..093050b03543 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -18,6 +18,7 @@ #include #include +#ifdef CONFIG_FPU extern void __fstate_save(struct task_struct *save_to); extern void __fstate_restore(struct task_struct *restore_from); @@ -55,6 +56,15 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_restore(next, task_pt_regs(next)); } +#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) + +#else +#define fstate_save(task, regs) do { } while (0) +#define fstate_restore(task, regs) do { } while (0) +#define __switch_to_aux(__prev, __next) do { } while (0) +#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_OFF) +#endif + extern struct task_struct *__switch_to(struct task_struct *, struct task_struct *); diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index bd433efd915e..f13f7f276639 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -13,7 +13,6 @@ extra-y += vmlinux.lds obj-y += cpu.o obj-y += cpufeature.o obj-y += entry.o -obj-y += fpu.o obj-y += irq.o obj-y += process.o obj-y += ptrace.o @@ -32,6 +31,7 @@ obj-y += vdso/ CFLAGS_setup.o := -mcmodel=medany +obj-$(CONFIG_FPU) += fpu.o obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index cb209139ba53..3820d89e2db9 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -83,7 +83,7 @@ void show_regs(struct pt_regs *regs) void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - regs->sstatus = SR_SPIE /* User mode, irqs on */ | SR_FS_INITIAL; + regs->sstatus = DEFAULT_SSTATUS; regs->sepc = pc; regs->sp = sp; set_fs(USER_DS); @@ -91,12 +91,14 @@ void start_thread(struct pt_regs *regs, unsigned long pc, void flush_thread(void) { +#ifdef CONFIG_FPU /* * Reset FPU context * frm: round to nearest, ties to even (IEEE default) * fflags: accrued exceptions cleared */ memset(¤t->thread.fstate, 0, sizeof(current->thread.fstate)); +#endif } int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 6a18b9819ead..2450b824d799 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,6 +37,7 @@ struct rt_sigframe { struct ucontext uc; }; +#ifdef CONFIG_FPU static long restore_fp_state(struct pt_regs *regs, union __riscv_fp_state *sc_fpregs) { @@ -85,6 +86,10 @@ static long save_fp_state(struct pt_regs *regs, return err; } +#else +#define save_fp_state(task, regs) (0) +#define restore_fp_state(task, regs) (0) +#endif static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) -- 2.18.0
[PATCH v5 2/5] Refactor FPU code in signal setup/return procedures
FPU-related logic is separated from normal signal handling path in this patch. Kernel can easily be configured to exclude those procedures for no-FPU systems. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/kernel/signal.c | 68 +++--- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 718d0c984ef0..6a18b9819ead 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,45 +37,63 @@ struct rt_sigframe { struct ucontext uc; }; -static long restore_d_state(struct pt_regs *regs, - struct __riscv_d_ext_state __user *state) +static long restore_fp_state(struct pt_regs *regs, +union __riscv_fp_state *sc_fpregs) { long err; + struct __riscv_d_ext_state __user *state = &sc_fpregs->d; + size_t i; + err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state)); - if (likely(!err)) - fstate_restore(current, regs); + if (unlikely(err)) + return err; + + fstate_restore(current, regs); + + /* We support no other extension state at this time. */ + for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { + u32 value; + + err = __get_user(value, &sc_fpregs->q.reserved[i]); + if (unlikely(err)) + break; + if (value != 0) + return -EINVAL; + } + return err; } -static long save_d_state(struct pt_regs *regs, - struct __riscv_d_ext_state __user *state) +static long save_fp_state(struct pt_regs *regs, + union __riscv_fp_state *sc_fpregs) { + long err; + struct __riscv_d_ext_state __user *state = &sc_fpregs->d; + size_t i; + fstate_save(current, regs); - return __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); + err = __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); + if (unlikely(err)) + return err; + + /* We support no other extension state at this time. */ + for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { + err = __put_user(0, &sc_fpregs->q.reserved[i]); + if (unlikely(err)) + break; + } + + return err; } static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { long err; - size_t i; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); - if (unlikely(err)) - return err; /* Restore the floating-point state. */ - err = restore_d_state(regs, &sc->sc_fpregs.d); - if (unlikely(err)) - return err; - /* We support no other extension state at this time. */ - for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) { - u32 value; - err = __get_user(value, &sc->sc_fpregs.q.reserved[i]); - if (unlikely(err)) - break; - if (value != 0) - return -EINVAL; - } + err |= restore_fp_state(regs, &sc->sc_fpregs); return err; } @@ -124,14 +142,10 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, { struct sigcontext __user *sc = &frame->uc.uc_mcontext; long err; - size_t i; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); /* Save the floating-point state. */ - err |= save_d_state(regs, &sc->sc_fpregs.d); - /* We support no other extension state at this time. */ - for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) - err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]); + err |= save_fp_state(regs, &sc->sc_fpregs); return err; } -- 2.18.0
[PATCH v5 3/5] Cleanup ISA string setting
Just a side note: (Assume that atomic and compressed is on) Before this patch, assembler was always given the riscv64imafdc MARCH string because there are fld/fsd's in entry.S; compiler was always given riscv64imac because kernel doesn't need floating point code generation. After this, the MARCH string in AFLAGS and CFLAGS become the same. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/Makefile | 19 --- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 6d4a5f6c3f4f..e0fe6790624f 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -26,7 +26,6 @@ ifeq ($(CONFIG_ARCH_RV64I),y) KBUILD_CFLAGS += -mabi=lp64 KBUILD_AFLAGS += -mabi=lp64 - KBUILD_MARCH = rv64im LDFLAGS += -melf64lriscv else BITS := 32 @@ -34,22 +33,20 @@ else KBUILD_CFLAGS += -mabi=ilp32 KBUILD_AFLAGS += -mabi=ilp32 - KBUILD_MARCH = rv32im LDFLAGS += -melf32lriscv endif KBUILD_CFLAGS += -Wall -ifeq ($(CONFIG_RISCV_ISA_A),y) - KBUILD_ARCH_A = a -endif -ifeq ($(CONFIG_RISCV_ISA_C),y) - KBUILD_ARCH_C = c -endif - -KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) +# ISA string setting +riscv-march-$(CONFIG_ARCH_RV32I) := rv32im +riscv-march-$(CONFIG_ARCH_RV64I) := rv64im +riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a +riscv-march-y := $(riscv-march-y)fd +riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c +KBUILD_CFLAGS += -march=$(riscv-march-y) +KBUILD_AFLAGS += -march=$(riscv-march-y) -KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C) KBUILD_CFLAGS += -mno-save-restore KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET) -- 2.18.0
[PATCH v5 1/5] Extract FPU context operations from entry.S
We move __fstate_save and __fstate_restore to a new source file, fpu.S. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/entry.S | 87 -- arch/riscv/kernel/fpu.S| 106 + 3 files changed, 107 insertions(+), 87 deletions(-) create mode 100644 arch/riscv/kernel/fpu.S diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index e1274fc03af4..bd433efd915e 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -13,6 +13,7 @@ extra-y += vmlinux.lds obj-y += cpu.o obj-y += cpufeature.o obj-y += entry.o +obj-y += fpu.o obj-y += irq.o obj-y += process.o obj-y += ptrace.o diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 9aaf6c986771..edcd5920ee4e 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -357,93 +357,6 @@ ENTRY(__switch_to) ret ENDPROC(__switch_to) -ENTRY(__fstate_save) - li a2, TASK_THREAD_F0 - add a0, a0, a2 - li t1, SR_FS - csrs sstatus, t1 - frcsr t0 - fsd f0, TASK_THREAD_F0_F0(a0) - fsd f1, TASK_THREAD_F1_F0(a0) - fsd f2, TASK_THREAD_F2_F0(a0) - fsd f3, TASK_THREAD_F3_F0(a0) - fsd f4, TASK_THREAD_F4_F0(a0) - fsd f5, TASK_THREAD_F5_F0(a0) - fsd f6, TASK_THREAD_F6_F0(a0) - fsd f7, TASK_THREAD_F7_F0(a0) - fsd f8, TASK_THREAD_F8_F0(a0) - fsd f9, TASK_THREAD_F9_F0(a0) - fsd f10, TASK_THREAD_F10_F0(a0) - fsd f11, TASK_THREAD_F11_F0(a0) - fsd f12, TASK_THREAD_F12_F0(a0) - fsd f13, TASK_THREAD_F13_F0(a0) - fsd f14, TASK_THREAD_F14_F0(a0) - fsd f15, TASK_THREAD_F15_F0(a0) - fsd f16, TASK_THREAD_F16_F0(a0) - fsd f17, TASK_THREAD_F17_F0(a0) - fsd f18, TASK_THREAD_F18_F0(a0) - fsd f19, TASK_THREAD_F19_F0(a0) - fsd f20, TASK_THREAD_F20_F0(a0) - fsd f21, TASK_THREAD_F21_F0(a0) - fsd f22, TASK_THREAD_F22_F0(a0) - fsd f23, TASK_THREAD_F23_F0(a0) - fsd f24, TASK_THREAD_F24_F0(a0) - fsd f25, TASK_THREAD_F25_F0(a0) - fsd f26, TASK_THREAD_F26_F0(a0) - fsd f27, TASK_THREAD_F27_F0(a0) - fsd f28, TASK_THREAD_F28_F0(a0) - fsd f29, TASK_THREAD_F29_F0(a0) - fsd f30, TASK_THREAD_F30_F0(a0) - fsd f31, TASK_THREAD_F31_F0(a0) - sw t0, TASK_THREAD_FCSR_F0(a0) - csrc sstatus, t1 - ret -ENDPROC(__fstate_save) - -ENTRY(__fstate_restore) - li a2, TASK_THREAD_F0 - add a0, a0, a2 - li t1, SR_FS - lw t0, TASK_THREAD_FCSR_F0(a0) - csrs sstatus, t1 - fld f0, TASK_THREAD_F0_F0(a0) - fld f1, TASK_THREAD_F1_F0(a0) - fld f2, TASK_THREAD_F2_F0(a0) - fld f3, TASK_THREAD_F3_F0(a0) - fld f4, TASK_THREAD_F4_F0(a0) - fld f5, TASK_THREAD_F5_F0(a0) - fld f6, TASK_THREAD_F6_F0(a0) - fld f7, TASK_THREAD_F7_F0(a0) - fld f8, TASK_THREAD_F8_F0(a0) - fld f9, TASK_THREAD_F9_F0(a0) - fld f10, TASK_THREAD_F10_F0(a0) - fld f11, TASK_THREAD_F11_F0(a0) - fld f12, TASK_THREAD_F12_F0(a0) - fld f13, TASK_THREAD_F13_F0(a0) - fld f14, TASK_THREAD_F14_F0(a0) - fld f15, TASK_THREAD_F15_F0(a0) - fld f16, TASK_THREAD_F16_F0(a0) - fld f17, TASK_THREAD_F17_F0(a0) - fld f18, TASK_THREAD_F18_F0(a0) - fld f19, TASK_THREAD_F19_F0(a0) - fld f20, TASK_THREAD_F20_F0(a0) - fld f21, TASK_THREAD_F21_F0(a0) - fld f22, TASK_THREAD_F22_F0(a0) - fld f23, TASK_THREAD_F23_F0(a0) - fld f24, TASK_THREAD_F24_F0(a0) - fld f25, TASK_THREAD_F25_F0(a0) - fld f26, TASK_THREAD_F26_F0(a0) - fld f27, TASK_THREAD_F27_F0(a0) - fld f28, TASK_THREAD_F28_F0(a0) - fld f29, TASK_THREAD_F29_F0(a0) - fld f30, TASK_THREAD_F30_F0(a0) - fld f31, TASK_THREAD_F31_F0(a0) - fscsr t0 - csrc sstatus, t1 - ret -ENDPROC(__fstate_restore) - - .section ".rodata" /* Exception vector table */ ENTRY(excp_vect_table) diff --git a/arch/riscv/kernel/fpu.S b/arch/riscv/kernel/fpu.S new file mode 100644 index ..1defb0618aff --- /dev/null +++ b/arch/riscv/kernel/fpu.S @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2012 Regents of the University of California + * Copyright (C) 2017 SiFive + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +
[PATCH v5 0/5] riscv: Add support to no-FPU systems
This patchset adds an option, CONFIG_FPU, to enable/disable floating- point procedures. Kernel's new behavior will be as follows: * with CONFIG_FPU=y All FPU codes are reserved. If no FPU is found during booting, a global flag will be set, and those functions will be bypassed with condition check to that flag. * with CONFIG_FPU=n No floating-point instructions in kernel and all related settings are excluded. Changes in v5: - Invert the polarity of checking flag from no_fpu to has_fpu. Changes in v4: - Append a new patch to detect existence of FPU and followups. - Add SPDX header to newly created fpu.S. - Fix a build error, sorry for that. - Fix wording, style, etc. Changes in v3: - Refactor the whole patch into independent ones. Changes in v2: - Various code cleanups and style fixes. Alan Kao (5): Extract FPU context operations from entry.S Refactor FPU code in signal setup/return procedures Cleanup ISA string setting Allow to disable FPU support Auto-detect whether a FPU exists arch/riscv/Kconfig | 9 +++ arch/riscv/Makefile| 19 +++--- arch/riscv/include/asm/hwcap.h | 1 + arch/riscv/include/asm/switch_to.h | 13 +++- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/cpufeature.c | 8 +++ arch/riscv/kernel/entry.S | 87 --- arch/riscv/kernel/fpu.S| 106 + arch/riscv/kernel/process.c| 6 +- arch/riscv/kernel/signal.c | 75 10 files changed, 198 insertions(+), 127 deletions(-) create mode 100644 arch/riscv/kernel/fpu.S -- 2.18.0
[PATCH v5 5/5] Auto-detect whether a FPU exists
We expect that a kernel with CONFIG_FPU=y can still support no-FPU machines. To do so, the kernel should first examine the existence of a FPU, then do nothing if a FPU does exist; otherwise, it should disable/bypass all FPU-related functions. In this patch, a new global variable, has_fpu, is created and determined when parsing the hardware capability from device tree during booting. This variable is used in those FPU-related functions. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/include/asm/hwcap.h | 1 + arch/riscv/include/asm/switch_to.h | 9 + arch/riscv/kernel/cpufeature.c | 8 arch/riscv/kernel/process.c| 4 +++- arch/riscv/kernel/signal.c | 6 -- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index 8a4ed7bbcbea..b0da2cbfb468 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -33,5 +33,6 @@ enum { }; extern unsigned long elf_hwcap; +extern bool has_fpu; #endif #endif diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index 093050b03543..7943f991bd86 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_FPU extern void __fstate_save(struct task_struct *save_to); @@ -56,13 +57,12 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_restore(next, task_pt_regs(next)); } -#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) - +extern bool has_fpu; #else +#define has_fpu false #define fstate_save(task, regs) do { } while (0) #define fstate_restore(task, regs) do { } while (0) #define __switch_to_aux(__prev, __next) do { } while (0) -#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_OFF) #endif extern struct task_struct *__switch_to(struct task_struct *, @@ -72,7 +72,8 @@ extern struct task_struct *__switch_to(struct task_struct *, do { \ struct task_struct *__prev = (prev);\ struct task_struct *__next = (next);\ - __switch_to_aux(__prev, __next);\ + if (has_fpu)\ + __switch_to_aux(__prev, __next);\ ((last) = __switch_to(__prev, __next)); \ } while (0) diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 17011a870044..46942e635266 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -22,6 +22,9 @@ #include unsigned long elf_hwcap __read_mostly; +#ifdef CONFIG_FPU +bool has_fpu __read_mostly; +#endif void riscv_fill_hwcap(void) { @@ -58,4 +61,9 @@ void riscv_fill_hwcap(void) elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; pr_info("elf_hwcap is 0x%lx", elf_hwcap); + +#ifdef CONFIG_FPU + if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)) + has_fpu = true; +#endif } diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 3820d89e2db9..97155aee9e71 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -83,7 +83,9 @@ void show_regs(struct pt_regs *regs) void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - regs->sstatus = DEFAULT_SSTATUS; + regs->sstatus = SR_SPIE; + if (has_fpu) + regs->sstatus |= SR_FS_INITIAL; regs->sepc = pc; regs->sp = sp; set_fs(USER_DS); diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 2450b824d799..f9b5e7e352ef 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -98,7 +98,8 @@ static long restore_sigcontext(struct pt_regs *regs, /* sc_regs is structured the same as the start of pt_regs */ err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); /* Restore the floating-point state. */ - err |= restore_fp_state(regs, &sc->sc_fpregs); + if (has_fpu) + err |= restore_fp_state(regs, &sc->sc_fpregs); return err; } @@ -150,7 +151,8 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); /* Save the floating-point state. */ - err |= save_fp_state(regs, &sc->sc_fpregs); + if (has_fpu) + err |= save_fp_state(regs, &sc->sc_fpregs); return err; } -- 2.18.0
Re: [PATCH v5 5/5] Auto-detect whether a FPU exists
On Wed, Aug 08, 2018 at 11:31:24PM -0700, Christoph Hellwig wrote: > > extern unsigned long elf_hwcap; > > +extern bool has_fpu; > > #endif > > Doesn't this conflict with the !CONFIG_CPU stub in switch_to.h? switch_to.h did include asm/hwcap.h, but the !CONFIG_FPU stub +#define has_fpu false always shows later than +extern bool has fpu so actually no warning during compilation. > > It seems like we should only have this definition in one place to start > with. It does look a little bit weird. Should I send a v6 for this? > > Otherwise this looks fine to me: > > Reviewed-by: Christoph Hellwig > Thanks for all the feedback. Alan
Re: [PATCH v5 5/5] Auto-detect whether a FPU exists
On Thu, Aug 09, 2018 at 12:02:58AM -0700, Christoph Hellwig wrote: > On Thu, Aug 09, 2018 at 02:43:36PM +0800, Alan Kao wrote: > > It does look a little bit weird. Should I send a v6 for this? > > Yes, please resend the series or just this patch. > > I think the hswap.h definition should go away and we should just > keep the switch_to.h one, even if that means including the header > in another C file. > It turns out that only cpufeature.c and switch_to.h are affected by hwcap.h. As switch_to.h already had extern has_fpu declaration, the one in hwcap.h is redundant and can be removed safely. I will resend just this patch, and mark it as v6.
[PATCH v6 5/5] Auto-detect whether a FPU exists
We expect that a kernel with CONFIG_FPU=y can still support no-FPU machines. To do so, the kernel should first examine the existence of a FPU, then do nothing if a FPU does exist; otherwise, it should disable/bypass all FPU-related functions. In this patch, a new global variable, has_fpu, is created and determined when parsing the hardware capability from device tree during booting. This variable is used in those FPU-related functions. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/include/asm/switch_to.h | 8 arch/riscv/kernel/cpufeature.c | 8 arch/riscv/kernel/process.c| 4 +++- arch/riscv/kernel/signal.c | 6 -- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index 093050b03543..733559083f24 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -56,13 +56,12 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_restore(next, task_pt_regs(next)); } -#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) - +extern bool has_fpu; #else +#define has_fpu false #define fstate_save(task, regs) do { } while (0) #define fstate_restore(task, regs) do { } while (0) #define __switch_to_aux(__prev, __next) do { } while (0) -#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_OFF) #endif extern struct task_struct *__switch_to(struct task_struct *, @@ -72,7 +71,8 @@ extern struct task_struct *__switch_to(struct task_struct *, do { \ struct task_struct *__prev = (prev);\ struct task_struct *__next = (next);\ - __switch_to_aux(__prev, __next);\ + if (has_fpu)\ + __switch_to_aux(__prev, __next);\ ((last) = __switch_to(__prev, __next)); \ } while (0) diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 17011a870044..46942e635266 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -22,6 +22,9 @@ #include unsigned long elf_hwcap __read_mostly; +#ifdef CONFIG_FPU +bool has_fpu __read_mostly; +#endif void riscv_fill_hwcap(void) { @@ -58,4 +61,9 @@ void riscv_fill_hwcap(void) elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; pr_info("elf_hwcap is 0x%lx", elf_hwcap); + +#ifdef CONFIG_FPU + if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)) + has_fpu = true; +#endif } diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 3820d89e2db9..97155aee9e71 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -83,7 +83,9 @@ void show_regs(struct pt_regs *regs) void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - regs->sstatus = DEFAULT_SSTATUS; + regs->sstatus = SR_SPIE; + if (has_fpu) + regs->sstatus |= SR_FS_INITIAL; regs->sepc = pc; regs->sp = sp; set_fs(USER_DS); diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 2450b824d799..f9b5e7e352ef 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -98,7 +98,8 @@ static long restore_sigcontext(struct pt_regs *regs, /* sc_regs is structured the same as the start of pt_regs */ err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); /* Restore the floating-point state. */ - err |= restore_fp_state(regs, &sc->sc_fpregs); + if (has_fpu) + err |= restore_fp_state(regs, &sc->sc_fpregs); return err; } @@ -150,7 +151,8 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); /* Save the floating-point state. */ - err |= save_fp_state(regs, &sc->sc_fpregs); + if (has_fpu) + err |= save_fp_state(regs, &sc->sc_fpregs); return err; } -- 2.18.0
Re: [PATCH v2] riscv: Add support to no-FPU systems
On Wed, Aug 01, 2018 at 10:55:28AM -0700, Palmer Dabbelt wrote: > On Tue, 26 Jun 2018 21:22:26 PDT (-0700), alan...@andestech.com wrote: > >This patch adds an option, CONFIG_FPU, to enable/disable floating > >procedures. Also, some style issues are fixed. > > > >Signed-off-by: Alan Kao > >Cc: Greentime Hu > >Cc: Zong Li > >--- > > arch/riscv/Kconfig | 9 > > arch/riscv/Makefile| 19 +++ > > arch/riscv/include/asm/switch_to.h | 6 +++ > > arch/riscv/kernel/entry.S | 3 +- > > arch/riscv/kernel/process.c| 7 ++- > > arch/riscv/kernel/signal.c | 82 +- > > 6 files changed, 90 insertions(+), 36 deletions(-) > > > >diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig > >index 6debcc4afc72..6069597ba73f 100644 > >--- a/arch/riscv/Kconfig > >+++ b/arch/riscv/Kconfig > >@@ -232,6 +232,15 @@ config RISCV_BASE_PMU > > > > endmenu > > > >+config FPU > >+bool "FPU support" > >+default y > >+help > >+ Say N here if you want to disable all floating-point related procedure > >+ in the kernel. > >+ > >+ If you don't know what to do here, say Y. > >+ > > endmenu > > Sorry for letting this slide for a bit. While I'm not opposed to a solution > that requires a FPU Kconfig option, it'd be a bit better if we could detect > this at boot time. I think this should be possible because at one point > this actually worked and we could boot the same kernel on FPU and no-FPU > systems. > > If that's not possible then we'll have to take something like this. There > were some comments on this v2 but I don't see a v3, did I miss one? I have been refatoring this into a patchset containing logically indenpendent patches. It will be sent soon after some sanity checks.
[PATCH v3 3/4] Cleanup ISA string setting
The reason that we cannot follow the review's suggestion in https://lkml.org/lkml/2018/6/21/39 is because using "+=" as the connector in Makefile introduces blanks bewteen the left-hand side alphabets. Note: (Assume that atomic and compressed is on) Before this patch, assembler was always given the riscv64imafdc MARCH string because there are fld/fsd's in entry.S; compiler was always given riscv64imac because kernel doesn't need floating point code generation. After this, the MARCH string in AFLAGS and CFLAGS become the same. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/Makefile | 19 --- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 6d4a5f6c3f4f..e0fe6790624f 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -26,7 +26,6 @@ ifeq ($(CONFIG_ARCH_RV64I),y) KBUILD_CFLAGS += -mabi=lp64 KBUILD_AFLAGS += -mabi=lp64 - KBUILD_MARCH = rv64im LDFLAGS += -melf64lriscv else BITS := 32 @@ -34,22 +33,20 @@ else KBUILD_CFLAGS += -mabi=ilp32 KBUILD_AFLAGS += -mabi=ilp32 - KBUILD_MARCH = rv32im LDFLAGS += -melf32lriscv endif KBUILD_CFLAGS += -Wall -ifeq ($(CONFIG_RISCV_ISA_A),y) - KBUILD_ARCH_A = a -endif -ifeq ($(CONFIG_RISCV_ISA_C),y) - KBUILD_ARCH_C = c -endif - -KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) +# ISA string setting +riscv-march-$(CONFIG_ARCH_RV32I) := rv32im +riscv-march-$(CONFIG_ARCH_RV64I) := rv64im +riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a +riscv-march-y := $(riscv-march-y)fd +riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c +KBUILD_CFLAGS += -march=$(riscv-march-y) +KBUILD_AFLAGS += -march=$(riscv-march-y) -KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C) KBUILD_CFLAGS += -mno-save-restore KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET) -- 2.18.0
[PATCH v3 0/4] riscv: Add support to no-FPU systems
This patchset adds an option, CONFIG_FPU, to enable/disable floating- point procedures. Changes in v3: - Refactor the whole patch into independent ones. Changes in v2: - Various code cleanups and style fixes. Alan Kao (4): Extract FPU context operations from entry.S Refactor FPU codes in signal setup/return procedures Cleanup ISA string setting Add an option to support no-FPU systems arch/riscv/Kconfig | 9 +++ arch/riscv/Makefile| 19 +++--- arch/riscv/include/asm/switch_to.h | 12 arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/entry.S | 87 arch/riscv/kernel/fpu.S| 105 + arch/riscv/kernel/process.c| 4 +- arch/riscv/kernel/signal.c | 70 +++ 8 files changed, 181 insertions(+), 126 deletions(-) create mode 100644 arch/riscv/kernel/fpu.S -- 2.18.0
[PATCH v3 2/4] Refactor FPU codes in signal setup/return procedures
Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/kernel/signal.c | 68 +++--- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 718d0c984ef0..bfce852d5ddc 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,45 +37,63 @@ struct rt_sigframe { struct ucontext uc; }; -static long restore_d_state(struct pt_regs *regs, - struct __riscv_d_ext_state __user *state) +static long restore_fp_state(struct pt_regs *regs, + union __riscv_fp_state *sc_fpregs) { long err; + struct __riscv_d_ext_state __user *state = &sc_fpregs->d; + size_t i; + err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state)); - if (likely(!err)) - fstate_restore(current, regs); + if (unlikely(err)) + return err; + + fstate_restore(current, regs); + + /* We support no other extension state at this time. */ + for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { + u32 value; + + err = __get_user(value, &sc_fpregs->q.reserved[i]); + if (unlikely(err)) + break; + if (value != 0) + return -EINVAL; + } + return err; } -static long save_d_state(struct pt_regs *regs, - struct __riscv_d_ext_state __user *state) +static long save_fp_state(struct pt_regs *regs, + union __riscv_fp_state *sc_fpregs) { + long err; + struct __riscv_d_ext_state __user *state = &sc_fpregs->d; + size_t i; + fstate_save(current, regs); - return __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); + err = __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); + if (unlikely(err)) + return err; + + /* We support no other extension state at this time. */ + for (i = 0; i < ARRAY_SIZE(sc_fpregs.q.reserved); i++) { + err = __put_user(0, &sc_fpregs.q.reserved[i]); + if (unlikely(err)) + break; + } + + return err; } static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { long err; - size_t i; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); - if (unlikely(err)) - return err; /* Restore the floating-point state. */ - err = restore_d_state(regs, &sc->sc_fpregs.d); - if (unlikely(err)) - return err; - /* We support no other extension state at this time. */ - for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) { - u32 value; - err = __get_user(value, &sc->sc_fpregs.q.reserved[i]); - if (unlikely(err)) - break; - if (value != 0) - return -EINVAL; - } + err |= restore_fp_state(regs, &sc->sc_fpregs); return err; } @@ -124,14 +142,10 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, { struct sigcontext __user *sc = &frame->uc.uc_mcontext; long err; - size_t i; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); /* Save the floating-point state. */ - err |= save_d_state(regs, &sc->sc_fpregs.d); - /* We support no other extension state at this time. */ - for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) - err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]); + err |= save_fp_state(regs, &sc->sc_fpregs); return err; } -- 2.18.0
[PATCH v3 4/4] Add an option to support no-FPU systems
FP codes have been separated from common part in previous patches. This patch add the CONFIG_FPU option and some stubs to support no-FPU systems. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/Kconfig | 9 + arch/riscv/include/asm/switch_to.h | 12 arch/riscv/kernel/Makefile | 2 +- arch/riscv/kernel/process.c| 4 +++- arch/riscv/kernel/signal.c | 2 ++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 6debcc4afc72..6069597ba73f 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -232,6 +232,15 @@ config RISCV_BASE_PMU endmenu +config FPU + bool "FPU support" + default y + help + Say N here if you want to disable all floating-point related procedure + in the kernel. + + If you don't know what to do here, say Y. + endmenu menu "Kernel type" diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index dd6b05bff75b..94a08d28ccf5 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -18,6 +18,7 @@ #include #include +#ifdef CONFIG_FPU extern void __fstate_save(struct task_struct *save_to); extern void __fstate_restore(struct task_struct *restore_from); @@ -55,6 +56,17 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_restore(next, task_pt_regs(next)); } +#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) + +#else +#define save_fp_state(task, regs) (0) +#define restore_fp_state(task, regs) (0) +#define fstate_save(task, regs) do { } while (0) +#define fstate_restore(task, regs) do { } while (0) +#define __switch_to_aux(__prev, __next) do { } while (0) +#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_OFF) +#endif + extern struct task_struct *__switch_to(struct task_struct *, struct task_struct *); diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index bd433efd915e..f13f7f276639 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -13,7 +13,6 @@ extra-y += vmlinux.lds obj-y += cpu.o obj-y += cpufeature.o obj-y += entry.o -obj-y += fpu.o obj-y += irq.o obj-y += process.o obj-y += ptrace.o @@ -32,6 +31,7 @@ obj-y += vdso/ CFLAGS_setup.o := -mcmodel=medany +obj-$(CONFIG_FPU) += fpu.o obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index cb209139ba53..3820d89e2db9 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -83,7 +83,7 @@ void show_regs(struct pt_regs *regs) void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - regs->sstatus = SR_SPIE /* User mode, irqs on */ | SR_FS_INITIAL; + regs->sstatus = DEFAULT_SSTATUS; regs->sepc = pc; regs->sp = sp; set_fs(USER_DS); @@ -91,12 +91,14 @@ void start_thread(struct pt_regs *regs, unsigned long pc, void flush_thread(void) { +#ifdef CONFIG_FPU /* * Reset FPU context * frm: round to nearest, ties to even (IEEE default) * fflags: accrued exceptions cleared */ memset(¤t->thread.fstate, 0, sizeof(current->thread.fstate)); +#endif } int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index bfce852d5ddc..b7bbb5c33594 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,6 +37,7 @@ struct rt_sigframe { struct ucontext uc; }; +#ifdef CONFIG_FPU static long restore_fp_state(struct pt_regs *regs, union __riscv_fp_state *sc_fpregs) { @@ -85,6 +86,7 @@ static long save_fp_state(struct pt_regs *regs, return err; } +#endif static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) -- 2.18.0
[PATCH v3 1/4] Extract FPU context operations from entry.S
We move __fstate_save and __fstate_restore to a new source file, fpu.S. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/entry.S | 87 -- arch/riscv/kernel/fpu.S| 105 + 3 files changed, 106 insertions(+), 87 deletions(-) create mode 100644 arch/riscv/kernel/fpu.S diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index e1274fc03af4..bd433efd915e 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -13,6 +13,7 @@ extra-y += vmlinux.lds obj-y += cpu.o obj-y += cpufeature.o obj-y += entry.o +obj-y += fpu.o obj-y += irq.o obj-y += process.o obj-y += ptrace.o diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 9aaf6c986771..edcd5920ee4e 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -357,93 +357,6 @@ ENTRY(__switch_to) ret ENDPROC(__switch_to) -ENTRY(__fstate_save) - li a2, TASK_THREAD_F0 - add a0, a0, a2 - li t1, SR_FS - csrs sstatus, t1 - frcsr t0 - fsd f0, TASK_THREAD_F0_F0(a0) - fsd f1, TASK_THREAD_F1_F0(a0) - fsd f2, TASK_THREAD_F2_F0(a0) - fsd f3, TASK_THREAD_F3_F0(a0) - fsd f4, TASK_THREAD_F4_F0(a0) - fsd f5, TASK_THREAD_F5_F0(a0) - fsd f6, TASK_THREAD_F6_F0(a0) - fsd f7, TASK_THREAD_F7_F0(a0) - fsd f8, TASK_THREAD_F8_F0(a0) - fsd f9, TASK_THREAD_F9_F0(a0) - fsd f10, TASK_THREAD_F10_F0(a0) - fsd f11, TASK_THREAD_F11_F0(a0) - fsd f12, TASK_THREAD_F12_F0(a0) - fsd f13, TASK_THREAD_F13_F0(a0) - fsd f14, TASK_THREAD_F14_F0(a0) - fsd f15, TASK_THREAD_F15_F0(a0) - fsd f16, TASK_THREAD_F16_F0(a0) - fsd f17, TASK_THREAD_F17_F0(a0) - fsd f18, TASK_THREAD_F18_F0(a0) - fsd f19, TASK_THREAD_F19_F0(a0) - fsd f20, TASK_THREAD_F20_F0(a0) - fsd f21, TASK_THREAD_F21_F0(a0) - fsd f22, TASK_THREAD_F22_F0(a0) - fsd f23, TASK_THREAD_F23_F0(a0) - fsd f24, TASK_THREAD_F24_F0(a0) - fsd f25, TASK_THREAD_F25_F0(a0) - fsd f26, TASK_THREAD_F26_F0(a0) - fsd f27, TASK_THREAD_F27_F0(a0) - fsd f28, TASK_THREAD_F28_F0(a0) - fsd f29, TASK_THREAD_F29_F0(a0) - fsd f30, TASK_THREAD_F30_F0(a0) - fsd f31, TASK_THREAD_F31_F0(a0) - sw t0, TASK_THREAD_FCSR_F0(a0) - csrc sstatus, t1 - ret -ENDPROC(__fstate_save) - -ENTRY(__fstate_restore) - li a2, TASK_THREAD_F0 - add a0, a0, a2 - li t1, SR_FS - lw t0, TASK_THREAD_FCSR_F0(a0) - csrs sstatus, t1 - fld f0, TASK_THREAD_F0_F0(a0) - fld f1, TASK_THREAD_F1_F0(a0) - fld f2, TASK_THREAD_F2_F0(a0) - fld f3, TASK_THREAD_F3_F0(a0) - fld f4, TASK_THREAD_F4_F0(a0) - fld f5, TASK_THREAD_F5_F0(a0) - fld f6, TASK_THREAD_F6_F0(a0) - fld f7, TASK_THREAD_F7_F0(a0) - fld f8, TASK_THREAD_F8_F0(a0) - fld f9, TASK_THREAD_F9_F0(a0) - fld f10, TASK_THREAD_F10_F0(a0) - fld f11, TASK_THREAD_F11_F0(a0) - fld f12, TASK_THREAD_F12_F0(a0) - fld f13, TASK_THREAD_F13_F0(a0) - fld f14, TASK_THREAD_F14_F0(a0) - fld f15, TASK_THREAD_F15_F0(a0) - fld f16, TASK_THREAD_F16_F0(a0) - fld f17, TASK_THREAD_F17_F0(a0) - fld f18, TASK_THREAD_F18_F0(a0) - fld f19, TASK_THREAD_F19_F0(a0) - fld f20, TASK_THREAD_F20_F0(a0) - fld f21, TASK_THREAD_F21_F0(a0) - fld f22, TASK_THREAD_F22_F0(a0) - fld f23, TASK_THREAD_F23_F0(a0) - fld f24, TASK_THREAD_F24_F0(a0) - fld f25, TASK_THREAD_F25_F0(a0) - fld f26, TASK_THREAD_F26_F0(a0) - fld f27, TASK_THREAD_F27_F0(a0) - fld f28, TASK_THREAD_F28_F0(a0) - fld f29, TASK_THREAD_F29_F0(a0) - fld f30, TASK_THREAD_F30_F0(a0) - fld f31, TASK_THREAD_F31_F0(a0) - fscsr t0 - csrc sstatus, t1 - ret -ENDPROC(__fstate_restore) - - .section ".rodata" /* Exception vector table */ ENTRY(excp_vect_table) diff --git a/arch/riscv/kernel/fpu.S b/arch/riscv/kernel/fpu.S new file mode 100644 index ..3210ef502e55 --- /dev/null +++ b/arch/riscv/kernel/fpu.S @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2012 Regents of the University of California + * Copyright (C) 2017 SiFive + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include +#include +#include + +ENTRY(__fstate_save) +
Re: [PATCH 2/6] riscv/ftrace: Add dynamic function tracer support
On Wed, Jan 10, 2018 at 11:36:43AM -0500, Steven Rostedt wrote: > On Wed, 10 Jan 2018 15:38:10 +0800 > Alan Kao wrote: > > > +static int __ftrace_modify_call(unsigned long hook_pos, unsigned long > > target, > > + bool enable) > > +{ > > + unsigned int offset = (unsigned int)(target - hook_pos); > > + unsigned int auipc_call = to_auipc_insn(offset); > > + unsigned int jalr_call = to_jalr_insn(offset); > > + unsigned int calls[2] = {auipc_call, jalr_call}; > > + unsigned int nops[2] = {NOP4, NOP4}; > > + int ret = 0; > > + > > + /* when ftrace_make_nop is called */ > > + if (!enable) > > + ret = ftrace_check_current_call(hook_pos, calls); > > + > > + if (ret) > > + goto out; > > + > > + /* replace the auipc-jalr pair at once */ > > + ret = probe_kernel_write((void *)hook_pos, enable ? calls : nops, > > +MCOUNT_INSN_SIZE); > > + if (ret) > > You don't want to return the return of probe_kernel_write() here. For > ftrace bug to work properly, if a fail to write occurs, you need to > return -EPERM. > > -- Steve > Thanks for the correction and the style fix in the previous mail. These problems will be fixed in the next version patch. Alan
[PATCH v3 5/6] riscv/ftrace: Add DYNAMIC_FTRACE_WITH_REGS support
Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 1 + arch/riscv/kernel/ftrace.c | 17 ++ arch/riscv/kernel/mcount-dyn.S | 124 + 3 files changed, 142 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index a5c5c88700d4..bb2c64976583 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -119,6 +119,7 @@ config ARCH_RV64I select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE + select HAVE_DYNAMIC_FTRACE_WITH_REGS endchoice diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index dce1286af9b0..3922b29c107b 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -105,6 +105,23 @@ int __init ftrace_dyn_arch_init(void) } #endif +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, + unsigned long addr) +{ + unsigned int offset = (unsigned int)(old_addr - rec->ip); + unsigned int auipc_call = to_auipc_insn(offset); + unsigned int jalr_call = to_jalr_insn(offset); + unsigned int calls[2] = {auipc_call, jalr_call}; + int ret = ftrace_check_current_call(rec->ip, calls); + + if (ret) + return ret; + + return __ftrace_modify_call(rec->ip, addr, true); +} +#endif + #ifdef CONFIG_FUNCTION_GRAPH_TRACER /* * Most of this function is copied from arm64. diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index c8959bdd4f38..e123ab7a8f32 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -115,3 +115,127 @@ ftrace_call: RESTORE_ABI_STATE ret ENDPROC(ftrace_caller) + + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + .macro SAVE_ALL + addisp, sp, -(PT_SIZE_ON_STACK+16) + sd s0, (PT_SIZE_ON_STACK)(sp) + sd ra, (PT_SIZE_ON_STACK+8)(sp) + addis0, sp, (PT_SIZE_ON_STACK+16) + + sd x1, PT_RA(sp) + sd x2, PT_SP(sp) + sd x3, PT_GP(sp) + sd x4, PT_TP(sp) + sd x5, PT_T0(sp) + sd x6, PT_T1(sp) + sd x7, PT_T2(sp) + sd x8, PT_S0(sp) + sd x9, PT_S1(sp) + sd x10, PT_A0(sp) + sd x11, PT_A1(sp) + sd x12, PT_A2(sp) + sd x13, PT_A3(sp) + sd x14, PT_A4(sp) + sd x15, PT_A5(sp) + sd x16, PT_A6(sp) + sd x17, PT_A7(sp) + sd x18, PT_S2(sp) + sd x19, PT_S3(sp) + sd x20, PT_S4(sp) + sd x21, PT_S5(sp) + sd x22, PT_S6(sp) + sd x23, PT_S7(sp) + sd x24, PT_S8(sp) + sd x25, PT_S9(sp) + sd x26, PT_S10(sp) + sd x27, PT_S11(sp) + sd x28, PT_T3(sp) + sd x29, PT_T4(sp) + sd x30, PT_T5(sp) + sd x31, PT_T6(sp) + .endm + + .macro RESTORE_ALL + ld x1, PT_RA(sp) + ld x2, PT_SP(sp) + ld x3, PT_GP(sp) + ld x4, PT_TP(sp) + ld x5, PT_T0(sp) + ld x6, PT_T1(sp) + ld x7, PT_T2(sp) + ld x8, PT_S0(sp) + ld x9, PT_S1(sp) + ld x10, PT_A0(sp) + ld x11, PT_A1(sp) + ld x12, PT_A2(sp) + ld x13, PT_A3(sp) + ld x14, PT_A4(sp) + ld x15, PT_A5(sp) + ld x16, PT_A6(sp) + ld x17, PT_A7(sp) + ld x18, PT_S2(sp) + ld x19, PT_S3(sp) + ld x20, PT_S4(sp) + ld x21, PT_S5(sp) + ld x22, PT_S6(sp) + ld x23, PT_S7(sp) + ld x24, PT_S8(sp) + ld x25, PT_S9(sp) + ld x26, PT_S10(sp) + ld x27, PT_S11(sp) + ld x28, PT_T3(sp) + ld x29, PT_T4(sp) + ld x30, PT_T5(sp) + ld x31, PT_T6(sp) + + ld s0, (PT_SIZE_ON_STACK)(sp) + ld ra, (PT_SIZE_ON_STACK+8)(sp) + addisp, sp, (PT_SIZE_ON_STACK+16) + .endm + + .macro RESTORE_GRAPH_REG_ARGS + ld a0, PT_T0(sp) + ld a1, PT_T1(sp) +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld a2, PT_T2(sp) +#endif + .endm + +/* + * Most of the contents are the same as ftrace_caller. + */ +ENTRY(ftrace_regs_caller) + /* +* a3: the address of all registers in the stack +*/ + ld a1, -8(s0) + addia0, ra, -MCOUNT_INSN_SIZE + la t5, function_trace_op + ld a2, 0(t5) + addia3, sp, -(PT_SIZE_ON_STACK+16) + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + addit0, s0, -8 + mv t1, a0 +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld t2, -16(s0) +#endif +#endif + SAVE_ALL + +ftrace_regs_call: + .global ftrace_regs_call + addix0, x0, 0 + addix0, x0, 0 + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + RESTORE_GRAPH_REG_ARGS + callftrace_graph_caller +#endif + + RESTORE_ALL + ret +ENDPROC(ftrace_regs_caller) +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ -- 2.15.1
[PATCH v3 0/6] Add dynamic ftrace support for RISC-V platforms
This patch set includes the building blocks of dynamic ftrace features for RISC-V machines. Changes in v3: - Replace the nops at the tracer call sites into a "call ftrace_stub" instruction for better understanding (1/6 and 2/6) Changes in v2: - Fix the return value as writing to kernel text goes wrong (2/6) - Replace manual comparisons by calling memcmp (2/6) - Simplify the conditional assignment in the Makefile (1/6) Alan Kao (6): riscv/ftrace: Add RECORD_MCOUNT support riscv/ftrace: Add dynamic function tracer support riscv/ftrace: Add dynamic function graph tracer support riscv/ftrace: Add ARCH_SUPPORTS_FTRACE_OPS support riscv/ftrace: Add DYNAMIC_FTRACE_WITH_REGS support riscv/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support arch/riscv/Kconfig | 3 + arch/riscv/Makefile | 3 + arch/riscv/include/asm/ftrace.h | 47 arch/riscv/kernel/Makefile | 5 +- arch/riscv/kernel/ftrace.c | 142 ++- arch/riscv/kernel/mcount-dyn.S | 241 arch/riscv/kernel/mcount.S | 22 ++-- arch/riscv/kernel/stacktrace.c | 6 + scripts/recordmcount.pl | 5 + 9 files changed, 461 insertions(+), 13 deletions(-) create mode 100644 arch/riscv/kernel/mcount-dyn.S -- 2.15.1
[PATCH v3 4/6] riscv/ftrace: Add ARCH_SUPPORTS_FTRACE_OPS support
Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/include/asm/ftrace.h | 1 + arch/riscv/kernel/mcount-dyn.S | 3 +++ 2 files changed, 4 insertions(+) diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index acf0c7d001f3..429a6a156645 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -9,6 +9,7 @@ #define HAVE_FUNCTION_GRAPH_FP_TEST #endif +#define ARCH_SUPPORTS_FTRACE_OPS 1 #ifndef __ASSEMBLY__ void _mcount(void); static inline unsigned long ftrace_call_adjust(unsigned long addr) diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 1ddf8b1a9345..c8959bdd4f38 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -74,9 +74,12 @@ ENTRY(ftrace_caller) /* * a0: the address in the caller when calling ftrace_caller * a1: the caller's return address +* a2: the address of global variable function_trace_op */ ld a1, -8(s0) addia0, ra, -MCOUNT_INSN_SIZE + la t5, function_trace_op + ld a2, 0(t5) #ifdef CONFIG_FUNCTION_GRAPH_TRACER /* -- 2.15.1
[PATCH v3 6/6] riscv/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support
In walk_stackframe, the pc now receives the address from calling ftrace_graph_ret_addr instead of manual calculation. Note that the original calculation, pc = frame->ra - 4 is buggy when the instruction at the return address happened to be a compressed inst. But since it is not a critical part of ftrace, it is ignored for now to ease the review process. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/include/asm/ftrace.h | 1 + arch/riscv/kernel/ftrace.c | 2 +- arch/riscv/kernel/stacktrace.c | 6 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 429a6a156645..6e4b4c96b63e 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -8,6 +8,7 @@ #if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER) #define HAVE_FUNCTION_GRAPH_FP_TEST #endif +#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR #define ARCH_SUPPORTS_FTRACE_OPS 1 #ifndef __ASSEMBLY__ diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 3922b29c107b..ded8ab25f4ad 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -150,7 +150,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, return; err = ftrace_push_return_trace(old, self_addr, &trace.depth, - frame_pointer, NULL); + frame_pointer, parent); if (err == -EBUSY) return; *parent = return_hooker; diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c index 559aae781154..a4b1d94371a0 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_FRAME_POINTER @@ -63,7 +64,12 @@ static void notrace walk_stackframe(struct task_struct *task, frame = (struct stackframe *)fp - 1; sp = fp; fp = frame->fp; +#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR + pc = ftrace_graph_ret_addr(current, NULL, frame->ra, + (unsigned long *)(fp - 8)); +#else pc = frame->ra - 0x4; +#endif } } -- 2.15.1
[PATCH v3 3/6] riscv/ftrace: Add dynamic function graph tracer support
Once the function_graph tracer is enabled, a filtered function has the following call sequence: * ftracer_caller ==> on/off by ftrace_make_call/ftrace_make_nop * ftrace_graph_caller * ftrace_graph_call ==> on/off by ftrace_en/disable_ftrace_graph_caller * prepare_ftrace_return Considering the following DYNAMIC_FTRACE_WITH_REGS feature, it would be more extendable to have a ftrace_graph_caller function, instead of calling prepare_ftrace_return directly in ftrace_caller. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/kernel/ftrace.c | 25 - arch/riscv/kernel/mcount-dyn.S | 64 ++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 311c287433c9..dce1286af9b0 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -51,7 +51,7 @@ static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target, unsigned int nops[2] = {NOP4, NOP4}; int ret = 0; - /* when ftrace_make_nop is called */ + /* for ftrace_make_nop and ftrace_disable_ftrace_graph_caller */ if (!enable) ret = ftrace_check_current_call(hook_pos, calls); @@ -105,6 +105,7 @@ int __init ftrace_dyn_arch_init(void) } #endif +#ifdef CONFIG_FUNCTION_GRAPH_TRACER /* * Most of this function is copied from arm64. */ @@ -137,3 +138,25 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, return; *parent = return_hooker; } + +#ifdef CONFIG_DYNAMIC_FTRACE +extern void ftrace_graph_call(void); +int ftrace_enable_ftrace_graph_caller(void) +{ + int ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call, + NULL); + + if (ret) + return ret; + + return __ftrace_modify_call((unsigned long)&ftrace_graph_call, + (unsigned long)&prepare_ftrace_return, true); +} + +int ftrace_disable_ftrace_graph_caller(void) +{ + return __ftrace_modify_call((unsigned long)&ftrace_graph_call, + (unsigned long)&prepare_ftrace_return, false); +} +#endif /* CONFIG_DYNAMIC_FTRACE */ +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 5731d9f56142..1ddf8b1a9345 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -14,18 +14,62 @@ .text .macro SAVE_ABI_STATE +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + addisp, sp, -48 + sd s0, 32(sp) + sd ra, 40(sp) + addis0, sp, 48 + sd t0, 24(sp) + sd t1, 16(sp) +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + sd t2, 8(sp) +#endif +#else addisp, sp, -16 sd s0, 0(sp) sd ra, 8(sp) addis0, sp, 16 +#endif .endm .macro RESTORE_ABI_STATE +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + ld s0, 32(sp) + ld ra, 40(sp) + addisp, sp, 48 +#else ld ra, 8(sp) ld s0, 0(sp) addisp, sp, 16 +#endif .endm + .macro RESTORE_GRAPH_ARGS + ld a0, 24(sp) + ld a1, 16(sp) +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld a2, 8(sp) +#endif + .endm + +ENTRY(ftrace_graph_caller) + addisp, sp, -16 + sd s0, 0(sp) + sd ra, 8(sp) + addis0, sp, 16 +ftrace_graph_call: + .global ftrace_graph_call + /* +* Calling ftrace_enable/disable_ftrace_graph_caller would overwrite the +* call below. Check ftrace_modify_all_code for details. +*/ + callftrace_stub + ld ra, 8(sp) + ld s0, 0(sp) + addisp, sp, 16 + ret +ENDPROC(ftrace_graph_caller) + ENTRY(ftrace_caller) /* * a0: the address in the caller when calling ftrace_caller @@ -33,6 +77,20 @@ ENTRY(ftrace_caller) */ ld a1, -8(s0) addia0, ra, -MCOUNT_INSN_SIZE + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + /* +* the graph tracer (specifically, prepare_ftrace_return) needs these +* arguments but for now the function tracer occupies the regs, so we +* save them in temporary regs to recover later. +*/ + addit0, s0, -8 + mv t1, a0 +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld t2, -16(s0) +#endif +#endif + SAVE_ABI_STATE ftrace_call: .global ftrace_call @@ -45,6 +103,12 @@ ftrace_call: * Check ftrace_modify_all_code for details. */ callftrace_stub + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + RESTORE_GRAPH_ARGS + callftrace_graph_caller +#endif + RESTORE_ABI_STATE ret ENDPROC(ftrace_caller) -- 2.15.1
[PATCH v3 1/6] riscv/ftrace: Add RECORD_MCOUNT support
Now recordmcount.pl recognizes RISC-V object files. For the mechanism to work, we have to disable the linker relaxation. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 1 + arch/riscv/Makefile | 3 +++ scripts/recordmcount.pl | 5 + 3 files changed, 9 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 40a67fc12328..1f45a76f412e 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -117,6 +117,7 @@ config ARCH_RV64I select 64BIT select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FTRACE_MCOUNT_RECORD endchoice diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 6719dd30ec5b..899226e0da7d 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -11,6 +11,9 @@ LDFLAGS := OBJCOPYFLAGS:= -O binary LDFLAGS_vmlinux := +ifeq ($(CONFIG_DYNAMIC_FTRACE),y) + LDFLAGS_vmlinux := --no-relax +endif KBUILD_AFLAGS_MODULE += -fPIC KBUILD_CFLAGS_MODULE += -fPIC diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 2033af758173..d44d55db7c06 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -376,6 +376,11 @@ if ($arch eq "x86_64") { $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s__mcount\$"; $type = ".quad"; $alignment = 8; +} elsif ($arch eq "riscv") { +$function_regex = "^([0-9a-fA-F]+)\\s+<([^.0-9][0-9a-zA-Z_\\.]+)>:"; +$mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL\\s_mcount\$"; +$type = ".quad"; +$alignment = 2; } else { die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; } -- 2.15.1
[PATCH v3 2/6] riscv/ftrace: Add dynamic function tracer support
We now have dynamic ftrace with the following added items: * ftrace_make_call, ftrace_make_nop (in kernel/ftrace.c) The two functions turns any recorded call site of filtered functions into a call to ftrace_caller or nops * ftracce_update_ftrace_func (in kernel/ftrace.c) turns the stub call at ftrace_call into a call to a generic entry for function tracers. * ftrace_caller (in kernel/mcount-dyn.S) The entry where each _mcount call sites calls to once they are filtered to be traced. Also, this patch fixes the semantic problems in mcount.S, which will be treated as only a reference implementation once we have the dynamic ftrace. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/ftrace.h | 45 ++ arch/riscv/kernel/Makefile | 5 +- arch/riscv/kernel/ftrace.c | 100 +++- arch/riscv/kernel/mcount-dyn.S | 50 arch/riscv/kernel/mcount.S | 22 + 6 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 arch/riscv/kernel/mcount-dyn.S diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 1f45a76f412e..a5c5c88700d4 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -118,6 +118,7 @@ config ARCH_RV64I select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FTRACE_MCOUNT_RECORD + select HAVE_DYNAMIC_FTRACE endchoice diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 66d4175eb13e..acf0c7d001f3 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -8,3 +8,48 @@ #if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER) #define HAVE_FUNCTION_GRAPH_FP_TEST #endif + +#ifndef __ASSEMBLY__ +void _mcount(void); +static inline unsigned long ftrace_call_adjust(unsigned long addr) +{ + return addr; +} + +struct dyn_arch_ftrace { +}; +#endif + +#ifdef CONFIG_DYNAMIC_FTRACE +/* + * A general call in RISC-V is a pair of insts: + * 1) auipc: setting high-20 pc-related bits to ra register + * 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to + * return address (original pc + 4) + * + * Dynamic ftrace generates probes to call sites, so we must deal with + * both auipc and jalr at the same time. + */ + +#define MCOUNT_ADDR((unsigned long)_mcount) +#define JALR_SIGN_MASK (0x0800) +#define JALR_OFFSET_MASK (0x0fff) +#define AUIPC_OFFSET_MASK (0xf000) +#define AUIPC_PAD (0x1000) +#define JALR_SHIFT 20 +#define JALR_BASIC (0x80e7) +#define AUIPC_BASIC(0x0097) +#define NOP4 (0x0013) + +#define to_jalr_insn(_offset) \ + (((_offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_BASIC) + +#define to_auipc_insn(_offset) ((_offset & JALR_SIGN_MASK) ? \ + (((_offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_BASIC) : \ + ((_offset & AUIPC_OFFSET_MASK) | AUIPC_BASIC)) + +/* + * Let auipc+jalr be the basic *mcount unit*, so we make it 8 bytes here. + */ +#define MCOUNT_INSN_SIZE 8 +#endif diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 196f62ffc428..d7bdf888f1ca 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -34,7 +34,8 @@ CFLAGS_setup.o := -mcmodel=medany obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_FUNCTION_TRACER) += mcount.o -obj-$(CONFIG_FUNCTION_GRAPH_TRACER)+= ftrace.o + +obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o +obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o clean: diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index d0de68d144cb..311c287433c9 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -6,9 +6,107 @@ */ #include +#include +#include + +#ifdef CONFIG_DYNAMIC_FTRACE +static int ftrace_check_current_call(unsigned long hook_pos, +unsigned int *expected) +{ + unsigned int replaced[2]; + unsigned int nops[2] = {NOP4, NOP4}; + + /* we expect nops at the hook position */ + if (!expected) + expected = nops; + + /* +* Read the text we want to modify; +* return must be -EFAULT on read error +*/ + if (probe_kernel_read(replaced, (void *)hook_pos, MCOUNT_INSN_SIZE)) + return -EFAULT; + + /* +* Make sure it is what we expect it to be; +* return must be -EINVAL on failed comparison +*/ + if (memcmp(expected, replaced, sizeof(replaced))) { + pr_err("%p: expected (%08x %08x) but get (%08x %08x)", + (void *)hook_pos, expected[0], expected[1], replaced[0], + repl
[PATCH 0/6] Add dynamic ftrace support for RISC-V platforms
This patch set includes the building blocks of dynamic ftraces features for RISC-V machines. Alan Kao (6): riscv/ftrace: Add RECORD_MCOUNT support riscv/ftrace: Add dynamic function tracer support riscv/ftrace: Add dynamic function graph tracer support riscv/ftrace: Add ARCH_SUPPORTS_FTRACE_OPS support riscv/ftrace: Add DYNAMIC_FTRACE_WITH_REGS support riscv/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support arch/riscv/Kconfig | 3 + arch/riscv/Makefile | 6 +- arch/riscv/include/asm/ftrace.h | 47 arch/riscv/kernel/Makefile | 5 +- arch/riscv/kernel/ftrace.c | 136 +- arch/riscv/kernel/mcount-dyn.S | 244 arch/riscv/kernel/mcount.S | 22 ++-- arch/riscv/kernel/stacktrace.c | 6 + scripts/recordmcount.pl | 5 + 9 files changed, 460 insertions(+), 14 deletions(-) create mode 100644 arch/riscv/kernel/mcount-dyn.S -- 2.15.1
[PATCH 2/6] riscv/ftrace: Add dynamic function tracer support
We now have dynamic ftrace with the following added items: * ftrace_make_call, ftrace_make_nop (in kernel/ftrace.c) The two functions turns any recorded call site of filtered functions into a call to ftrace_caller or nops * ftracce_update_ftrace_func (in kernel/ftrace.c) turns the nops at ftrace_call into a call to a generic entry for function tracers. * ftrace_caller (in kernel/mcount-dyn.S) The entry where each _mcount call site calls to once the function is filtered to be traced. Also, this patch fixes the semantic problems in mcount.S, which will be treated as only a reference implementation once we have the dynamic ftrace. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/ftrace.h | 45 arch/riscv/kernel/Makefile | 5 ++- arch/riscv/kernel/ftrace.c | 94 - arch/riscv/kernel/mcount-dyn.S | 52 +++ arch/riscv/kernel/mcount.S | 22 ++ 6 files changed, 207 insertions(+), 12 deletions(-) create mode 100644 arch/riscv/kernel/mcount-dyn.S diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 346dd1b0fb05..96db66272db5 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -113,6 +113,7 @@ config ARCH_RV64I select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FTRACE_MCOUNT_RECORD + select HAVE_DYNAMIC_FTRACE endchoice diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 66d4175eb13e..acf0c7d001f3 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -8,3 +8,48 @@ #if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER) #define HAVE_FUNCTION_GRAPH_FP_TEST #endif + +#ifndef __ASSEMBLY__ +void _mcount(void); +static inline unsigned long ftrace_call_adjust(unsigned long addr) +{ + return addr; +} + +struct dyn_arch_ftrace { +}; +#endif + +#ifdef CONFIG_DYNAMIC_FTRACE +/* + * A general call in RISC-V is a pair of insts: + * 1) auipc: setting high-20 pc-related bits to ra register + * 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to + * return address (original pc + 4) + * + * Dynamic ftrace generates probes to call sites, so we must deal with + * both auipc and jalr at the same time. + */ + +#define MCOUNT_ADDR((unsigned long)_mcount) +#define JALR_SIGN_MASK (0x0800) +#define JALR_OFFSET_MASK (0x0fff) +#define AUIPC_OFFSET_MASK (0xf000) +#define AUIPC_PAD (0x1000) +#define JALR_SHIFT 20 +#define JALR_BASIC (0x80e7) +#define AUIPC_BASIC(0x0097) +#define NOP4 (0x0013) + +#define to_jalr_insn(_offset) \ + (((_offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_BASIC) + +#define to_auipc_insn(_offset) ((_offset & JALR_SIGN_MASK) ? \ + (((_offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_BASIC) : \ + ((_offset & AUIPC_OFFSET_MASK) | AUIPC_BASIC)) + +/* + * Let auipc+jalr be the basic *mcount unit*, so we make it 8 bytes here. + */ +#define MCOUNT_INSN_SIZE 8 +#endif diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 196f62ffc428..d7bdf888f1ca 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -34,7 +34,8 @@ CFLAGS_setup.o := -mcmodel=medany obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_FUNCTION_TRACER) += mcount.o -obj-$(CONFIG_FUNCTION_GRAPH_TRACER)+= ftrace.o + +obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o +obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o clean: diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index d0de68d144cb..49d2d799f532 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -6,9 +6,101 @@ */ #include +#include +#include + +#ifdef CONFIG_DYNAMIC_FTRACE +static int ftrace_check_current_call(unsigned long hook_pos, +unsigned int *expected) +{ + unsigned int replaced[2]; + unsigned int nops[2] = {NOP4, NOP4}; + + /* we expect nops at the hook position */ + if (!expected) + expected = nops; + + /* read the text we want to modify */ + if (probe_kernel_read(replaced, (void *)hook_pos, MCOUNT_INSN_SIZE)) + return -EFAULT; + + /* Make sure it is what we expect it to be */ + if (replaced[0] != expected[0] || replaced[1] != expected[1]) { + pr_err("%p: expected (%08x %08x) but get (%08x %08x)", + (void *)hook_pos, expected[0], expected[1], replaced[0], + replaced[1]); + return -EINVAL; + } + + return 0; +} + +static int __ftrace_modify_call(unsi
[PATCH 4/6] riscv/ftrace: Add ARCH_SUPPORTS_FTRACE_OPS support
Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/include/asm/ftrace.h | 1 + arch/riscv/kernel/mcount-dyn.S | 3 +++ 2 files changed, 4 insertions(+) diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index acf0c7d001f3..429a6a156645 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -9,6 +9,7 @@ #define HAVE_FUNCTION_GRAPH_FP_TEST #endif +#define ARCH_SUPPORTS_FTRACE_OPS 1 #ifndef __ASSEMBLY__ void _mcount(void); static inline unsigned long ftrace_call_adjust(unsigned long addr) diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 64e715d4e180..627478571c7a 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -75,9 +75,12 @@ ENTRY(ftrace_caller) /* * a0: the address in the caller when calling ftrace_caller * a1: the caller's return address +* a2: the address of global variable function_trace_op */ ld a1, -8(s0) addia0, ra, -MCOUNT_INSN_SIZE + la t5, function_trace_op + ld a2, 0(t5) #ifdef CONFIG_FUNCTION_GRAPH_TRACER /* -- 2.15.1
[PATCH 5/6] riscv/ftrace: Add DYNAMIC_FTRACE_WITH_REGS support
Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 1 + arch/riscv/kernel/ftrace.c | 17 ++ arch/riscv/kernel/mcount-dyn.S | 124 + 3 files changed, 142 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 96db66272db5..06685bcf5643 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -114,6 +114,7 @@ config ARCH_RV64I select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE + select HAVE_DYNAMIC_FTRACE_WITH_REGS endchoice diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 239ef5d56f24..c9cc884961d7 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -99,6 +99,23 @@ int __init ftrace_dyn_arch_init(void) } #endif +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, + unsigned long addr) +{ + unsigned int offset = (unsigned int)(old_addr - rec->ip); + unsigned int auipc_call = to_auipc_insn(offset); + unsigned int jalr_call = to_jalr_insn(offset); + unsigned int calls[2] = {auipc_call, jalr_call}; + int ret = ftrace_check_current_call(rec->ip, calls); + + if (ret) + return ret; + + return __ftrace_modify_call(rec->ip, addr, true); +} +#endif + #ifdef CONFIG_FUNCTION_GRAPH_TRACER /* * Most of this function is copied from arm64. diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 627478571c7a..3ec3ddbfb5e7 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -118,3 +118,127 @@ ftrace_call: RESTORE_ABI_STATE ret ENDPROC(ftrace_caller) + + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + .macro SAVE_ALL + addisp, sp, -(PT_SIZE_ON_STACK+16) + sd s0, (PT_SIZE_ON_STACK)(sp) + sd ra, (PT_SIZE_ON_STACK+8)(sp) + addis0, sp, (PT_SIZE_ON_STACK+16) + + sd x1, PT_RA(sp) + sd x2, PT_SP(sp) + sd x3, PT_GP(sp) + sd x4, PT_TP(sp) + sd x5, PT_T0(sp) + sd x6, PT_T1(sp) + sd x7, PT_T2(sp) + sd x8, PT_S0(sp) + sd x9, PT_S1(sp) + sd x10, PT_A0(sp) + sd x11, PT_A1(sp) + sd x12, PT_A2(sp) + sd x13, PT_A3(sp) + sd x14, PT_A4(sp) + sd x15, PT_A5(sp) + sd x16, PT_A6(sp) + sd x17, PT_A7(sp) + sd x18, PT_S2(sp) + sd x19, PT_S3(sp) + sd x20, PT_S4(sp) + sd x21, PT_S5(sp) + sd x22, PT_S6(sp) + sd x23, PT_S7(sp) + sd x24, PT_S8(sp) + sd x25, PT_S9(sp) + sd x26, PT_S10(sp) + sd x27, PT_S11(sp) + sd x28, PT_T3(sp) + sd x29, PT_T4(sp) + sd x30, PT_T5(sp) + sd x31, PT_T6(sp) + .endm + + .macro RESTORE_ALL + ld x1, PT_RA(sp) + ld x2, PT_SP(sp) + ld x3, PT_GP(sp) + ld x4, PT_TP(sp) + ld x5, PT_T0(sp) + ld x6, PT_T1(sp) + ld x7, PT_T2(sp) + ld x8, PT_S0(sp) + ld x9, PT_S1(sp) + ld x10, PT_A0(sp) + ld x11, PT_A1(sp) + ld x12, PT_A2(sp) + ld x13, PT_A3(sp) + ld x14, PT_A4(sp) + ld x15, PT_A5(sp) + ld x16, PT_A6(sp) + ld x17, PT_A7(sp) + ld x18, PT_S2(sp) + ld x19, PT_S3(sp) + ld x20, PT_S4(sp) + ld x21, PT_S5(sp) + ld x22, PT_S6(sp) + ld x23, PT_S7(sp) + ld x24, PT_S8(sp) + ld x25, PT_S9(sp) + ld x26, PT_S10(sp) + ld x27, PT_S11(sp) + ld x28, PT_T3(sp) + ld x29, PT_T4(sp) + ld x30, PT_T5(sp) + ld x31, PT_T6(sp) + + ld s0, (PT_SIZE_ON_STACK)(sp) + ld ra, (PT_SIZE_ON_STACK+8)(sp) + addisp, sp, (PT_SIZE_ON_STACK+16) + .endm + + .macro RESTORE_GRAPH_REG_ARGS + ld a0, PT_T0(sp) + ld a1, PT_T1(sp) +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld a2, PT_T2(sp) +#endif + .endm + +/* + * Most of the contents are the same as ftrace_caller. + */ +ENTRY(ftrace_regs_caller) + /* +* a3: the address of all registers in the stack +*/ + ld a1, -8(s0) + addia0, ra, -MCOUNT_INSN_SIZE + la t5, function_trace_op + ld a2, 0(t5) + addia3, sp, -(PT_SIZE_ON_STACK+16) + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + addit0, s0, -8 + mv t1, a0 +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld t2, -16(s0) +#endif +#endif + SAVE_ALL + +ftrace_regs_call: + .global ftrace_regs_call + addix0, x0, 0 + addix0, x0, 0 + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + RESTORE_GRAPH_REG_ARGS + callftrace_graph_caller +#endif + + RESTORE_ALL + ret +ENDPROC(ftrace_regs_caller) +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ -- 2.15.1
[PATCH 6/6] riscv/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support
When doing unwinding in the function walk_stackframe, the pc now receives the address from calling ftrace_graph_ret_addr instead of manual calculation. Note that the original expression, pc = frame->ra - 4 is buggy if the instruction at the return address happened to be a compressed inst. But since it is not a critical part of ftrace and is a RISC-V-specific behavior, it is ignored for now to ease the review process. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/include/asm/ftrace.h | 1 + arch/riscv/kernel/ftrace.c | 2 +- arch/riscv/kernel/stacktrace.c | 6 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 429a6a156645..6e4b4c96b63e 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -8,6 +8,7 @@ #if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER) #define HAVE_FUNCTION_GRAPH_FP_TEST #endif +#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR #define ARCH_SUPPORTS_FTRACE_OPS 1 #ifndef __ASSEMBLY__ diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index c9cc884961d7..e02ecd44fe47 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -144,7 +144,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, return; err = ftrace_push_return_trace(old, self_addr, &trace.depth, - frame_pointer, NULL); + frame_pointer, parent); if (err == -EBUSY) return; *parent = return_hooker; diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c index 559aae781154..a4b1d94371a0 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_FRAME_POINTER @@ -63,7 +64,12 @@ static void notrace walk_stackframe(struct task_struct *task, frame = (struct stackframe *)fp - 1; sp = fp; fp = frame->fp; +#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR + pc = ftrace_graph_ret_addr(current, NULL, frame->ra, + (unsigned long *)(fp - 8)); +#else pc = frame->ra - 0x4; +#endif } } -- 2.15.1
[PATCH 1/6] riscv/ftrace: Add RECORD_MCOUNT support
Now recordmcount.pl recognizes RISC-V object files. For the mechanism to work, we have to disable the linker relaxation. This is because relaxation happens after the script records offsets of _mcount call sites, resulting in a unreliable record. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 1 + arch/riscv/Makefile | 6 +- scripts/recordmcount.pl | 5 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 504ba386b22e..346dd1b0fb05 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -112,6 +112,7 @@ config ARCH_RV64I select 64BIT select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FTRACE_MCOUNT_RECORD endchoice diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 6719dd30ec5b..2bc39c6d9662 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -10,7 +10,11 @@ LDFLAGS := OBJCOPYFLAGS:= -O binary -LDFLAGS_vmlinux := +ifeq ($(CONFIG_DYNAMIC_FTRACE),y) + LDFLAGS_vmlinux := --no-relax +else + LDFLAGS_vmlinux := +endif KBUILD_AFLAGS_MODULE += -fPIC KBUILD_CFLAGS_MODULE += -fPIC diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 2033af758173..d44d55db7c06 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -376,6 +376,11 @@ if ($arch eq "x86_64") { $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s__mcount\$"; $type = ".quad"; $alignment = 8; +} elsif ($arch eq "riscv") { +$function_regex = "^([0-9a-fA-F]+)\\s+<([^.0-9][0-9a-zA-Z_\\.]+)>:"; +$mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL\\s_mcount\$"; +$type = ".quad"; +$alignment = 2; } else { die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; } -- 2.15.1
[PATCH 3/6] riscv/ftrace: Add dynamic function graph tracer support
Once the function_graph tracer is enabled, a filtered function has the following call sequence: * ftracer_caller ==> on/off by ftrace_make_call/ftrace_make_nop * ftrace_graph_caller * ftrace_graph_call ==> on/off by ftrace_en/disable_ftrace_graph_caller * prepare_ftrace_return Considering that the DYNAMIC_FTRACE_WITH_REGS feature, which introduces another hook entry ftrace_regs_caller, will access to ftrace_graph_call when needed, it would be more extendable to have a ftrace_graph_caller function, instead of calling prepare_ftrace_return directly in ftrace_caller. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/kernel/ftrace.c | 25 +++- arch/riscv/kernel/mcount-dyn.S | 65 ++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 49d2d799f532..239ef5d56f24 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -45,7 +45,7 @@ static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target, unsigned int nops[2] = {NOP4, NOP4}; int ret = 0; - /* when ftrace_make_nop is called */ + /* for ftrace_make_nop and ftrace_disable_ftrace_graph_caller */ if (!enable) ret = ftrace_check_current_call(hook_pos, calls); @@ -99,6 +99,7 @@ int __init ftrace_dyn_arch_init(void) } #endif +#ifdef CONFIG_FUNCTION_GRAPH_TRACER /* * Most of this function is copied from arm64. */ @@ -131,3 +132,25 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, return; *parent = return_hooker; } + +#ifdef CONFIG_DYNAMIC_FTRACE +extern void ftrace_graph_call(void); +int ftrace_enable_ftrace_graph_caller(void) +{ + int ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call, + NULL); + + if (ret) + return ret; + + return __ftrace_modify_call((unsigned long)&ftrace_graph_call, + (unsigned long)&prepare_ftrace_return, true); +} + +int ftrace_disable_ftrace_graph_caller(void) +{ + return __ftrace_modify_call((unsigned long)&ftrace_graph_call, + (unsigned long)&prepare_ftrace_return, false); +} +#endif /* CONFIG_DYNAMIC_FTRACE */ +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 57f80fe09cbd..64e715d4e180 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -14,18 +14,63 @@ .text .macro SAVE_ABI_STATE +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + addisp, sp, -48 + sd s0, 32(sp) + sd ra, 40(sp) + addis0, sp, 48 + sd t0, 24(sp) + sd t1, 16(sp) +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + sd t2, 8(sp) +#endif +#else addisp, sp, -16 sd s0, 0(sp) sd ra, 8(sp) addis0, sp, 16 +#endif .endm .macro RESTORE_ABI_STATE +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + ld s0, 32(sp) + ld ra, 40(sp) + addisp, sp, 48 +#else ld ra, 8(sp) ld s0, 0(sp) addisp, sp, 16 +#endif .endm + .macro RESTORE_GRAPH_ARGS + ld a0, 24(sp) + ld a1, 16(sp) +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld a2, 8(sp) +#endif + .endm + +ENTRY(ftrace_graph_caller) + addisp, sp, -16 + sd s0, 0(sp) + sd ra, 8(sp) + addis0, sp, 16 +ftrace_graph_call: + .global ftrace_graph_call + /* +* Calling ftrace_enable/disable_ftrace_graph_caller would overwrite the +* nops below. Check ftrace_modify_all_code for details. +*/ + addix0, x0, 0 + addix0, x0, 0 + ld ra, 8(sp) + ld s0, 0(sp) + addisp, sp, 16 + ret +ENDPROC(ftrace_graph_caller) + ENTRY(ftrace_caller) /* * a0: the address in the caller when calling ftrace_caller @@ -33,6 +78,20 @@ ENTRY(ftrace_caller) */ ld a1, -8(s0) addia0, ra, -MCOUNT_INSN_SIZE + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + /* +* the graph tracer (specifically, prepare_ftrace_return) needs these +* arguments but for now the function tracer occupies the regs, so we +* save them in temporary regs to recover later. +*/ + addit0, s0, -8 + mv t1, a0 +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld t2, -16(s0) +#endif +#endif + SAVE_ABI_STATE ftrace_call: .global ftrace_call @@ -47,6 +106,12 @@ ftrace_call: */ addix0, x0, 0 addix0, x0, 0 + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + RESTORE_GRAPH_ARGS + callftrace_graph_caller +#endif +
Re: [patches] [PATCH 1/6] riscv/ftrace: Add RECORD_MCOUNT support
On Wed, Jan 10, 2018 at 08:43:54AM +0100, Christoph Hellwig wrote: > On Wed, Jan 10, 2018 at 03:38:09PM +0800, Alan Kao wrote: > > -LDFLAGS_vmlinux := > > +ifeq ($(CONFIG_DYNAMIC_FTRACE),y) > > + LDFLAGS_vmlinux := --no-relax > > +else > > + LDFLAGS_vmlinux := > > +endif > > Why not: > > LDFLAGS_vmlinux := > ifeq ($(CONFIG_DYNAMIC_FTRACE),y) > LDFLAGS_vmlinux += --no-relax > endif > Thanks for the comment! This will be enhanced in the next try. Alan
[PATCH v2 0/6] Add dynamic ftrace support for RISC-V platforms
This patch set includes the building blocks of dynamic ftrace features for RISC-V machines. Changes in v2: - Fix the return value as writing to kernel text goes wrong (2/6) - Replace manual comparisons by calling memcmp (2/6) - Simplify the conditional assignment in the Makefile (1/6) Alan Kao (6): riscv/ftrace: Add RECORD_MCOUNT support riscv/ftrace: Add dynamic function tracer support riscv/ftrace: Add dynamic function graph tracer support riscv/ftrace: Add ARCH_SUPPORTS_FTRACE_OPS support riscv/ftrace: Add DYNAMIC_FTRACE_WITH_REGS support riscv/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support arch/riscv/Kconfig | 3 + arch/riscv/Makefile | 3 + arch/riscv/include/asm/ftrace.h | 47 arch/riscv/kernel/Makefile | 5 +- arch/riscv/kernel/ftrace.c | 142 ++- arch/riscv/kernel/mcount-dyn.S | 244 arch/riscv/kernel/mcount.S | 22 ++-- arch/riscv/kernel/stacktrace.c | 6 + scripts/recordmcount.pl | 5 + 9 files changed, 464 insertions(+), 13 deletions(-) create mode 100644 arch/riscv/kernel/mcount-dyn.S -- 2.15.1
[PATCH v2 6/6] riscv/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support
In walk_stackframe, the pc now receives the address from calling ftrace_graph_ret_addr instead of manual calculation. Note that the original calculation, pc = frame->ra - 4 is buggy when the instruction at the return address happened to be a compressed inst. But since it is not a critical part of ftrace, it is ignored for now to ease the review process. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/include/asm/ftrace.h | 1 + arch/riscv/kernel/ftrace.c | 2 +- arch/riscv/kernel/stacktrace.c | 6 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 429a6a156645..6e4b4c96b63e 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -8,6 +8,7 @@ #if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER) #define HAVE_FUNCTION_GRAPH_FP_TEST #endif +#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR #define ARCH_SUPPORTS_FTRACE_OPS 1 #ifndef __ASSEMBLY__ diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 3922b29c107b..ded8ab25f4ad 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -150,7 +150,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, return; err = ftrace_push_return_trace(old, self_addr, &trace.depth, - frame_pointer, NULL); + frame_pointer, parent); if (err == -EBUSY) return; *parent = return_hooker; diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c index 559aae781154..a4b1d94371a0 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_FRAME_POINTER @@ -63,7 +64,12 @@ static void notrace walk_stackframe(struct task_struct *task, frame = (struct stackframe *)fp - 1; sp = fp; fp = frame->fp; +#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR + pc = ftrace_graph_ret_addr(current, NULL, frame->ra, + (unsigned long *)(fp - 8)); +#else pc = frame->ra - 0x4; +#endif } } -- 2.15.1
[PATCH v2 1/6] riscv/ftrace: Add RECORD_MCOUNT support
Now recordmcount.pl recognizes RISC-V object files. For the mechanism to work, we have to disable the linker relaxation. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 1 + arch/riscv/Makefile | 3 +++ scripts/recordmcount.pl | 5 + 3 files changed, 9 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 40a67fc12328..1f45a76f412e 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -117,6 +117,7 @@ config ARCH_RV64I select 64BIT select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FTRACE_MCOUNT_RECORD endchoice diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 6719dd30ec5b..899226e0da7d 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -11,6 +11,9 @@ LDFLAGS := OBJCOPYFLAGS:= -O binary LDFLAGS_vmlinux := +ifeq ($(CONFIG_DYNAMIC_FTRACE),y) + LDFLAGS_vmlinux := --no-relax +endif KBUILD_AFLAGS_MODULE += -fPIC KBUILD_CFLAGS_MODULE += -fPIC diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 2033af758173..d44d55db7c06 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -376,6 +376,11 @@ if ($arch eq "x86_64") { $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s__mcount\$"; $type = ".quad"; $alignment = 8; +} elsif ($arch eq "riscv") { +$function_regex = "^([0-9a-fA-F]+)\\s+<([^.0-9][0-9a-zA-Z_\\.]+)>:"; +$mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL\\s_mcount\$"; +$type = ".quad"; +$alignment = 2; } else { die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; } -- 2.15.1
[PATCH v2 4/6] riscv/ftrace: Add ARCH_SUPPORTS_FTRACE_OPS support
Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/include/asm/ftrace.h | 1 + arch/riscv/kernel/mcount-dyn.S | 3 +++ 2 files changed, 4 insertions(+) diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index acf0c7d001f3..429a6a156645 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -9,6 +9,7 @@ #define HAVE_FUNCTION_GRAPH_FP_TEST #endif +#define ARCH_SUPPORTS_FTRACE_OPS 1 #ifndef __ASSEMBLY__ void _mcount(void); static inline unsigned long ftrace_call_adjust(unsigned long addr) diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 64e715d4e180..627478571c7a 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -75,9 +75,12 @@ ENTRY(ftrace_caller) /* * a0: the address in the caller when calling ftrace_caller * a1: the caller's return address +* a2: the address of global variable function_trace_op */ ld a1, -8(s0) addia0, ra, -MCOUNT_INSN_SIZE + la t5, function_trace_op + ld a2, 0(t5) #ifdef CONFIG_FUNCTION_GRAPH_TRACER /* -- 2.15.1
[PATCH v2 2/6] riscv/ftrace: Add dynamic function tracer support
We now have dynamic ftrace with the following added items: * ftrace_make_call, ftrace_make_nop (in kernel/ftrace.c) The two functions turns any recorded call site of filtered functions into a call to ftrace_caller or nops * ftracce_update_ftrace_func (in kernel/ftrace.c) turns the nops at ftrace_call into a call to a generic entry for function tracers. * ftrace_caller (in kernel/mcount-dyn.S) The entry where each _mcount call sites calls to once they are filtered to be traced. Also, this patch fixes the semantic problems in mcount.S, which will be treated as only a reference implementation once we have the dynamic ftrace. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/ftrace.h | 45 ++ arch/riscv/kernel/Makefile | 5 +- arch/riscv/kernel/ftrace.c | 100 +++- arch/riscv/kernel/mcount-dyn.S | 52 + arch/riscv/kernel/mcount.S | 22 + 6 files changed, 213 insertions(+), 12 deletions(-) create mode 100644 arch/riscv/kernel/mcount-dyn.S diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 1f45a76f412e..a5c5c88700d4 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -118,6 +118,7 @@ config ARCH_RV64I select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FTRACE_MCOUNT_RECORD + select HAVE_DYNAMIC_FTRACE endchoice diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 66d4175eb13e..acf0c7d001f3 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -8,3 +8,48 @@ #if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER) #define HAVE_FUNCTION_GRAPH_FP_TEST #endif + +#ifndef __ASSEMBLY__ +void _mcount(void); +static inline unsigned long ftrace_call_adjust(unsigned long addr) +{ + return addr; +} + +struct dyn_arch_ftrace { +}; +#endif + +#ifdef CONFIG_DYNAMIC_FTRACE +/* + * A general call in RISC-V is a pair of insts: + * 1) auipc: setting high-20 pc-related bits to ra register + * 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to + * return address (original pc + 4) + * + * Dynamic ftrace generates probes to call sites, so we must deal with + * both auipc and jalr at the same time. + */ + +#define MCOUNT_ADDR((unsigned long)_mcount) +#define JALR_SIGN_MASK (0x0800) +#define JALR_OFFSET_MASK (0x0fff) +#define AUIPC_OFFSET_MASK (0xf000) +#define AUIPC_PAD (0x1000) +#define JALR_SHIFT 20 +#define JALR_BASIC (0x80e7) +#define AUIPC_BASIC(0x0097) +#define NOP4 (0x0013) + +#define to_jalr_insn(_offset) \ + (((_offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_BASIC) + +#define to_auipc_insn(_offset) ((_offset & JALR_SIGN_MASK) ? \ + (((_offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_BASIC) : \ + ((_offset & AUIPC_OFFSET_MASK) | AUIPC_BASIC)) + +/* + * Let auipc+jalr be the basic *mcount unit*, so we make it 8 bytes here. + */ +#define MCOUNT_INSN_SIZE 8 +#endif diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 196f62ffc428..d7bdf888f1ca 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -34,7 +34,8 @@ CFLAGS_setup.o := -mcmodel=medany obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_FUNCTION_TRACER) += mcount.o -obj-$(CONFIG_FUNCTION_GRAPH_TRACER)+= ftrace.o + +obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o +obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o clean: diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index d0de68d144cb..311c287433c9 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -6,9 +6,107 @@ */ #include +#include +#include + +#ifdef CONFIG_DYNAMIC_FTRACE +static int ftrace_check_current_call(unsigned long hook_pos, +unsigned int *expected) +{ + unsigned int replaced[2]; + unsigned int nops[2] = {NOP4, NOP4}; + + /* we expect nops at the hook position */ + if (!expected) + expected = nops; + + /* +* Read the text we want to modify; +* return must be -EFAULT on read error +*/ + if (probe_kernel_read(replaced, (void *)hook_pos, MCOUNT_INSN_SIZE)) + return -EFAULT; + + /* +* Make sure it is what we expect it to be; +* return must be -EINVAL on failed comparison +*/ + if (memcmp(expected, replaced, sizeof(replaced))) { + pr_err("%p: expected (%08x %08x) but get (%08x %08x)", + (void *)hook_pos, expected[0], expected[1], replaced[0], + repl
[PATCH v2 5/6] riscv/ftrace: Add DYNAMIC_FTRACE_WITH_REGS support
Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 1 + arch/riscv/kernel/ftrace.c | 17 ++ arch/riscv/kernel/mcount-dyn.S | 124 + 3 files changed, 142 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index a5c5c88700d4..bb2c64976583 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -119,6 +119,7 @@ config ARCH_RV64I select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE + select HAVE_DYNAMIC_FTRACE_WITH_REGS endchoice diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index dce1286af9b0..3922b29c107b 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -105,6 +105,23 @@ int __init ftrace_dyn_arch_init(void) } #endif +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, + unsigned long addr) +{ + unsigned int offset = (unsigned int)(old_addr - rec->ip); + unsigned int auipc_call = to_auipc_insn(offset); + unsigned int jalr_call = to_jalr_insn(offset); + unsigned int calls[2] = {auipc_call, jalr_call}; + int ret = ftrace_check_current_call(rec->ip, calls); + + if (ret) + return ret; + + return __ftrace_modify_call(rec->ip, addr, true); +} +#endif + #ifdef CONFIG_FUNCTION_GRAPH_TRACER /* * Most of this function is copied from arm64. diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 627478571c7a..3ec3ddbfb5e7 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -118,3 +118,127 @@ ftrace_call: RESTORE_ABI_STATE ret ENDPROC(ftrace_caller) + + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + .macro SAVE_ALL + addisp, sp, -(PT_SIZE_ON_STACK+16) + sd s0, (PT_SIZE_ON_STACK)(sp) + sd ra, (PT_SIZE_ON_STACK+8)(sp) + addis0, sp, (PT_SIZE_ON_STACK+16) + + sd x1, PT_RA(sp) + sd x2, PT_SP(sp) + sd x3, PT_GP(sp) + sd x4, PT_TP(sp) + sd x5, PT_T0(sp) + sd x6, PT_T1(sp) + sd x7, PT_T2(sp) + sd x8, PT_S0(sp) + sd x9, PT_S1(sp) + sd x10, PT_A0(sp) + sd x11, PT_A1(sp) + sd x12, PT_A2(sp) + sd x13, PT_A3(sp) + sd x14, PT_A4(sp) + sd x15, PT_A5(sp) + sd x16, PT_A6(sp) + sd x17, PT_A7(sp) + sd x18, PT_S2(sp) + sd x19, PT_S3(sp) + sd x20, PT_S4(sp) + sd x21, PT_S5(sp) + sd x22, PT_S6(sp) + sd x23, PT_S7(sp) + sd x24, PT_S8(sp) + sd x25, PT_S9(sp) + sd x26, PT_S10(sp) + sd x27, PT_S11(sp) + sd x28, PT_T3(sp) + sd x29, PT_T4(sp) + sd x30, PT_T5(sp) + sd x31, PT_T6(sp) + .endm + + .macro RESTORE_ALL + ld x1, PT_RA(sp) + ld x2, PT_SP(sp) + ld x3, PT_GP(sp) + ld x4, PT_TP(sp) + ld x5, PT_T0(sp) + ld x6, PT_T1(sp) + ld x7, PT_T2(sp) + ld x8, PT_S0(sp) + ld x9, PT_S1(sp) + ld x10, PT_A0(sp) + ld x11, PT_A1(sp) + ld x12, PT_A2(sp) + ld x13, PT_A3(sp) + ld x14, PT_A4(sp) + ld x15, PT_A5(sp) + ld x16, PT_A6(sp) + ld x17, PT_A7(sp) + ld x18, PT_S2(sp) + ld x19, PT_S3(sp) + ld x20, PT_S4(sp) + ld x21, PT_S5(sp) + ld x22, PT_S6(sp) + ld x23, PT_S7(sp) + ld x24, PT_S8(sp) + ld x25, PT_S9(sp) + ld x26, PT_S10(sp) + ld x27, PT_S11(sp) + ld x28, PT_T3(sp) + ld x29, PT_T4(sp) + ld x30, PT_T5(sp) + ld x31, PT_T6(sp) + + ld s0, (PT_SIZE_ON_STACK)(sp) + ld ra, (PT_SIZE_ON_STACK+8)(sp) + addisp, sp, (PT_SIZE_ON_STACK+16) + .endm + + .macro RESTORE_GRAPH_REG_ARGS + ld a0, PT_T0(sp) + ld a1, PT_T1(sp) +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld a2, PT_T2(sp) +#endif + .endm + +/* + * Most of the contents are the same as ftrace_caller. + */ +ENTRY(ftrace_regs_caller) + /* +* a3: the address of all registers in the stack +*/ + ld a1, -8(s0) + addia0, ra, -MCOUNT_INSN_SIZE + la t5, function_trace_op + ld a2, 0(t5) + addia3, sp, -(PT_SIZE_ON_STACK+16) + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + addit0, s0, -8 + mv t1, a0 +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld t2, -16(s0) +#endif +#endif + SAVE_ALL + +ftrace_regs_call: + .global ftrace_regs_call + addix0, x0, 0 + addix0, x0, 0 + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + RESTORE_GRAPH_REG_ARGS + callftrace_graph_caller +#endif + + RESTORE_ALL + ret +ENDPROC(ftrace_regs_caller) +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ -- 2.15.1
[PATCH v2 3/6] riscv/ftrace: Add dynamic function graph tracer support
Once the function_graph tracer is enabled, a filtered function has the following call sequence: * ftracer_caller ==> on/off by ftrace_make_call/ftrace_make_nop * ftrace_graph_caller * ftrace_graph_call ==> on/off by ftrace_en/disable_ftrace_graph_caller * prepare_ftrace_return Considering the following DYNAMIC_FTRACE_WITH_REGS feature, it would be more extendable to have a ftrace_graph_caller function, instead of calling prepare_ftrace_return directly in ftrace_caller. Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/kernel/ftrace.c | 25 +++- arch/riscv/kernel/mcount-dyn.S | 65 ++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 311c287433c9..dce1286af9b0 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -51,7 +51,7 @@ static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target, unsigned int nops[2] = {NOP4, NOP4}; int ret = 0; - /* when ftrace_make_nop is called */ + /* for ftrace_make_nop and ftrace_disable_ftrace_graph_caller */ if (!enable) ret = ftrace_check_current_call(hook_pos, calls); @@ -105,6 +105,7 @@ int __init ftrace_dyn_arch_init(void) } #endif +#ifdef CONFIG_FUNCTION_GRAPH_TRACER /* * Most of this function is copied from arm64. */ @@ -137,3 +138,25 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, return; *parent = return_hooker; } + +#ifdef CONFIG_DYNAMIC_FTRACE +extern void ftrace_graph_call(void); +int ftrace_enable_ftrace_graph_caller(void) +{ + int ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call, + NULL); + + if (ret) + return ret; + + return __ftrace_modify_call((unsigned long)&ftrace_graph_call, + (unsigned long)&prepare_ftrace_return, true); +} + +int ftrace_disable_ftrace_graph_caller(void) +{ + return __ftrace_modify_call((unsigned long)&ftrace_graph_call, + (unsigned long)&prepare_ftrace_return, false); +} +#endif /* CONFIG_DYNAMIC_FTRACE */ +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 57f80fe09cbd..64e715d4e180 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -14,18 +14,63 @@ .text .macro SAVE_ABI_STATE +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + addisp, sp, -48 + sd s0, 32(sp) + sd ra, 40(sp) + addis0, sp, 48 + sd t0, 24(sp) + sd t1, 16(sp) +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + sd t2, 8(sp) +#endif +#else addisp, sp, -16 sd s0, 0(sp) sd ra, 8(sp) addis0, sp, 16 +#endif .endm .macro RESTORE_ABI_STATE +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + ld s0, 32(sp) + ld ra, 40(sp) + addisp, sp, 48 +#else ld ra, 8(sp) ld s0, 0(sp) addisp, sp, 16 +#endif .endm + .macro RESTORE_GRAPH_ARGS + ld a0, 24(sp) + ld a1, 16(sp) +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld a2, 8(sp) +#endif + .endm + +ENTRY(ftrace_graph_caller) + addisp, sp, -16 + sd s0, 0(sp) + sd ra, 8(sp) + addis0, sp, 16 +ftrace_graph_call: + .global ftrace_graph_call + /* +* Calling ftrace_enable/disable_ftrace_graph_caller would overwrite the +* nops below. Check ftrace_modify_all_code for details. +*/ + addix0, x0, 0 + addix0, x0, 0 + ld ra, 8(sp) + ld s0, 0(sp) + addisp, sp, 16 + ret +ENDPROC(ftrace_graph_caller) + ENTRY(ftrace_caller) /* * a0: the address in the caller when calling ftrace_caller @@ -33,6 +78,20 @@ ENTRY(ftrace_caller) */ ld a1, -8(s0) addia0, ra, -MCOUNT_INSN_SIZE + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + /* +* the graph tracer (specifically, prepare_ftrace_return) needs these +* arguments but for now the function tracer occupies the regs, so we +* save them in temporary regs to recover later. +*/ + addit0, s0, -8 + mv t1, a0 +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + ld t2, -16(s0) +#endif +#endif + SAVE_ABI_STATE ftrace_call: .global ftrace_call @@ -47,6 +106,12 @@ ftrace_call: */ addix0, x0, 0 addix0, x0, 0 + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + RESTORE_GRAPH_ARGS + callftrace_graph_caller +#endif + RESTORE_ABI_STATE ret ENDPROC(ftrace_caller) -- 2.15.1
Re: [patches] [PATCH v2 2/6] riscv/ftrace: Add dynamic function tracer support
On Sun, Jan 14, 2018 at 11:24:53PM -0800, Stefan O'Rear wrote: > On Sun, Jan 14, 2018 at 10:47 PM, Alan Kao wrote: > > + /* > > +* For the dynamic ftrace to work, here we should reserve at least > > +* 8 bytes for a functional auipc-jalr pair. Pseudo inst nop may be > > +* interpreted as different length in different models, so we > > manually > > +* *expand* two 4-byte nops here. > > +* > > +* Calling ftrace_update_ftrace_func would overwrite the nops below. > > +* Check ftrace_modify_all_code for details. > > +*/ > > + addix0, x0, 0 > > + addix0, x0, 0 > > This relies on behavior of the assembler which is undocumented and, if > my reading of the specification is correct, a bug. > > The documented way to assemble an sequence of 2 4-byte NOPs regardless > of subtarget is as follows: > > .option push > .option norvc > nop > nop > .option pop > > I have filed https://github.com/riscv/riscv-binutils-gdb/issues/135 to > get clarity on the assembler behavior; the explicit approach may be > preferable even if the assembler behavior turns out to be correct. > > -s > Thanks for pointing this out. After checking the way other architectures have done this, I think we can just put a call ftrace_stub here. Currently we don't support linker relaxing with ftrace, so this macro will be expand to 8-byte inst-pair. Alan > -- > You received this message because you are subscribed to the Google Groups > "RISC-V Patches" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to patches+unsubscr...@groups.riscv.org. > To post to this group, send email to patc...@groups.riscv.org. > Visit this group at > https://groups.google.com/a/groups.riscv.org/group/patches/. > To view this discussion on the web visit > https://groups.google.com/a/groups.riscv.org/d/msgid/patches/CADJ6UvOZz%3DWZ18wYVhZcH0u58u_snDxmgbwsfTOS2ski-4O7tg%40mail.gmail.com. > For more options, visit https://groups.google.com/a/groups.riscv.org/d/optout.
Re: ftrace: Proposal for an Alternative RecordMcount framework
On Thu, Mar 01, 2018 at 10:05:07AM +0800, Alan Kao wrote: > On Wed, Feb 28, 2018 at 05:12:52AM +0800, Steven Rostedt wrote: > > On Tue, 27 Feb 2018 18:04:26 +0800 > > Alan Kao wrote: > > > > > 1. During the final linking stages, do "objdump vmlinux.o | grep ..." [2] > > > > Note, doing it at that stage takes the longest time. It makes small > > changes much longer to compile. That said... > > > > What if we can have some option to *disable* all the recordmcount.pl lauches > after every .o? There will be only an oneshot grep for a near-complete > vmlinux binary. > > > > 2. Form the output as an ELF objecj > > > 3. Link the object to __mcount_loc_start symbol > > > 4. Done > > > > > > With the similar reason as the patch [3], we should mark _mcount to be > > > a weak symbol to prevent it from being relaxed later. > > > > > > We would like to know your opinion and comments on this. > > > Thanks! > > > > What about just having your arch use recordmcount.c instead? It doesn't > > do any grepping. It is an elf reader and modifier and modifies the .o > > file directly. > > Thanks for the hint. But after a quick scan, it seems that recordmcount.c > processes .o files in a per-file basis, which means that we will still > suffer from the linker relaxation problem. > > > > > Note, I will be rewriting that code in the near future too, to > > consolidate it with objtool. > > > > -- Steve > > Please allow me to state the problem more clearly here. I hope this helps. > > 1. locations of mcount are recorded in a per-file basis. > 2. to optimize the binary, the linker turns on some aggressive >options, including relaxation. > 3. the optimizations changes the original offset. > 4. already recorded mcount call-sites no longer point to their >real positions. > 5. still a linked vmlinux is made. > 6. dynamic ftrace breaks the real logic in the kernel space, >panics happen. > > Thanks, > Alan Any comments on this? BTW, the introduced framework has no effects on any other architectures that works fine. This feature should be configurable and turned on only when the arch has aggressive link-time optimizations. If you consider this appropriate, I will send the patch to this once it gets ready. Currently this is targeting at RISC-V and upcoming NDS32. Thanks, Alan
[PATCH 2/2] perf: riscv: Add Document for Future Porting Guide
Cc: Nick Hu Cc: Greentime Hu Signed-off-by: Alan Kao --- Documentation/riscv/pmu.txt | 250 1 file changed, 250 insertions(+) create mode 100644 Documentation/riscv/pmu.txt diff --git a/Documentation/riscv/pmu.txt b/Documentation/riscv/pmu.txt new file mode 100644 index ..496f00476560 --- /dev/null +++ b/Documentation/riscv/pmu.txt @@ -0,0 +1,250 @@ +Supporting PMUs on RISC-V platforms +== +Alan Kao , Mar 2018 + +Introduction + + +As of this writing, perf_event-related features mentioned in The RISC-V ISA +Privileged Version 1.10 are as follows: +(please check the manual for more details) + +* [m|s]counteren +* mcycle[h], cycle[h] +* minstret[h], instret[h] +* mhpeventx, mhpcounterx[h] + +With such function set only, porting perf would require a lot of work, due to +the lack of the following general architectural performance monitoring features: + +* Enabling/Disabling counters + Counters are just free-running all the time in our case. +* Interrupt caused by counter overflow + No such design in the spec. +* Interrupt indicator + It is not possible to have many interrupt ports for all counters, so an + interrupt indicator is required for software to tell which counter has + just overflowed. +* Writing to counters + There will be an SBI to support this since the kernel cannot modify the + counters [1]. Alternatively, some vendor considers to implement + hardware-extension for M-S-U model machines to write counters directly. + +This document aims to provide developers a quick guide on supporting their +PMUs in the kernel. The following sections briefly explain perf' mechanism +and todos. + +You may check previous discussions here [1][2]. Also, it might be helpful +to check the appendix for related kernel structures. + + +1. Initialization +- + +*riscv_pmu* is a global pointer of type *struct riscv_pmu*, which contains +various methods according to perf's internal convention and PMU-specific +parameters. One should declare such instance to represent the PMU. By default, +*riscv_pmu* points to a constant structure *riscv_base_pmu*, which has very +basic support to a baseline QEMU model. + +Then he/she can either assign the instance's pointer to *riscv_pmu* so that +the minimal and already-implemented logic can be leveraged, or invent his/her +own *riscv_init_platform_pmu* implementation. + +In other words, existing sources of *riscv_base_pmu* merely provide a +reference implementation. Developers can flexibly decide how many parts they +can leverage, and in the most extreme case, they can customize every function +according to their needs. + + +2. Event Initialization +--- + +When a user launches a perf command to monitor some events, it is first +interpreted by the userspace perf tool into multiple *perf_event_open* +system calls, and then each of them calls to the body of *event_init* +member function that was assigned in the previous step. In *riscv_base_pmu*'s +case, it is *riscv_event_init*. + +The main purpose of this function is to translate the event provided by user +into bitmap, so that HW-related control registers or counters can directly be +manipulated. The translation is based on the mappings and methods provided in +*riscv_pmu*. + +Note that some features can be done in this stage as well: + +(1) interrupt setting, which is stated in the next section; +(2) privilege level setting (user space only, kernel space only, both); +(3) destructor setting. Normally it is sufficient to apply *riscv_destroy_event*; +(4) tweaks for non-sampling events, which will be utilized by functions such as +*perf_adjust_period*, usually something like the follows: + +if (!is_sampling_event(event)) { +hwc->sample_period = x86_pmu.max_period; +hwc->last_period = hwc->sample_period; +local64_set(&hwc->period_left, hwc->sample_period); +} + +In the case of *riscv_base_pmu*, only (3) is provided for now. + + +3. Interrupt + + +3.1. Interrupt Initialization + +This often occurs at the beginning of the *event_init* method. In common +practice, this should be a code segment like + +int x86_reserve_hardware(void) +{ +int err = 0; + +if (!atomic_inc_not_zero(&pmc_refcount)) { +mutex_lock(&pmc_reserve_mutex); +if (atomic_read(&pmc_refcount) == 0) { +if (!reserve_pmc_hardware()) +err = -EBUSY; +else +reserve_ds_buffers(); +} +if (!err) +atomic_inc(&pmc_refcount); +mutex_unlock(&pmc_reserve_mutex); +} + +return err; +} + +And the magic is in *reserve_pmc_hardware*, which usually does atomic +operations to make im
[PATCH 0/2] perf: riscv: Preliminary Perf Event Support on RISC-V
This implements the baseline PMU for RISC-V platforms. To ease the future PMU portings, a guide is also written, containing perf concepts, arch porting practices and some hints. Alan Kao (2): perf: riscv: preliminary RISC-V support perf: riscv: Add Document for Future Porting Guide Documentation/riscv/pmu.txt | 250 +++ arch/riscv/Kconfig | 12 + arch/riscv/include/asm/perf_event.h | 76 +- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/perf_event.c | 469 5 files changed, 804 insertions(+), 4 deletions(-) create mode 100644 Documentation/riscv/pmu.txt create mode 100644 arch/riscv/kernel/perf_event.c -- 2.16.2
[PATCH 1/2] perf: riscv: preliminary RISC-V support
This patch provide a basic PMU, riscv_base_pmu, which supports two general hardware event, instructions and cycles. Furthermore, this PMU serves as a reference implementation to ease the portings in the future. riscv_base_pmu should be able to run on any RISC-V machine that conforms to the Priv-Spec. Note that the latest qemu model hasn't fully support a proper behavior of Priv-Spec 1.10 yet, but work around should be easy with very small fixes. Please check https://github.com/riscv/riscv-qemu/pull/115 for future updates. Cc: Nick Hu Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 12 + arch/riscv/include/asm/perf_event.h | 76 +- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/perf_event.c | 469 4 files changed, 554 insertions(+), 4 deletions(-) create mode 100644 arch/riscv/kernel/perf_event.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 310b9a5d6737..dd4aecfb5265 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -195,6 +195,18 @@ config RISCV_ISA_C config RISCV_ISA_A def_bool y +menu "PMU type" + depends on PERF_EVENTS + +config RISCV_BASE_PMU + bool "Base Performance Monitoring Unit" + def_bool y + help + A base PMU that serves as a reference implementation and has limited + feature of perf. + +endmenu + endmenu menu "Kernel type" diff --git a/arch/riscv/include/asm/perf_event.h b/arch/riscv/include/asm/perf_event.h index e13d2ff29e83..98e2efb02d25 100644 --- a/arch/riscv/include/asm/perf_event.h +++ b/arch/riscv/include/asm/perf_event.h @@ -1,13 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2018 SiFive + * Copyright (C) 2018 Andes Technology Corporation * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #ifndef _ASM_RISCV_PERF_EVENT_H #define _ASM_RISCV_PERF_EVENT_H +#include +#include + +#define RISCV_BASE_COUNTERS2 + +/* + * The RISCV_MAX_COUNTERS parameter should be specified. + */ + +#ifdef CONFIG_RISCV_BASE_PMU +#define RISCV_MAX_COUNTERS 2 +#endif + +#ifndef RISCV_MAX_COUNTERS +#error "Please provide a valid RISCV_MAX_COUNTERS for the PMU." +#endif + +/* + * These are the indexes of bits in counteren register *minus* 1, + * except for cycle. It would be coherent if it can directly mapped + * to counteren bit definition, but there is a *time* register at + * counteren[1]. Per-cpu structure is scarce resource here. + * + * According to the spec, an implementation can support counter up to + * mhpmcounter31, but many high-end processors has at most 6 general + * PMCs, we give the definition to MHPMCOUNTER8 here. + */ +#define RISCV_PMU_CYCLE0 +#define RISCV_PMU_INSTRET 1 +#define RISCV_PMU_MHPMCOUNTER3 2 +#define RISCV_PMU_MHPMCOUNTER4 3 +#define RISCV_PMU_MHPMCOUNTER5 4 +#define RISCV_PMU_MHPMCOUNTER6 5 +#define RISCV_PMU_MHPMCOUNTER7 6 +#define RISCV_PMU_MHPMCOUNTER8 7 + +#define RISCV_OP_UNSUPP(-EOPNOTSUPP) + +struct cpu_hw_events { + /* # currently enabled events*/ + int n_events; + /* currently enabled events */ + struct perf_event *events[RISCV_MAX_COUNTERS]; + /* vendor-defined PMU data */ + void*platform; +}; + +struct riscv_pmu { + struct pmu *pmu; + + /* generic hw/cache events table */ + const int *hw_events; + const int (*cache_events)[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX]; + /* method used to map hw/cache events */ + int (*map_hw_event)(u64 config); + int (*map_cache_event)(u64 config); + + /* max generic hw events in map */ + int max_events; + /* number total counters, 2(base) + x(general) */ + int num_counters; + /* the width of the counter */ + int counter_width; + + /* vendor-defined PMU features */ + void*platform; +}; + #endif /* _ASM_RISCV_PERF_EVENT_H */ diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 196f62ffc428..849c38d9105f 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -36,5 +36,6 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER)+= ftrace.o +obj-$(CONFIG_PERF_EVENTS) += perf_event.o clean: diff --git a/arch/riscv/kernel/perf_event.c b/arch/riscv/kernel/perf_event.c new file mode 100644 i
Re: [PATCH 1/2] perf: riscv: preliminary RISC-V support
On Thu, Apr 05, 2018 at 09:47:50AM -0700, Palmer Dabbelt wrote: > On Mon, 26 Mar 2018 00:57:54 PDT (-0700), alan...@andestech.com wrote: > >This patch provide a basic PMU, riscv_base_pmu, which supports two > >general hardware event, instructions and cycles. Furthermore, this > >PMU serves as a reference implementation to ease the portings in > >the future. > > > >riscv_base_pmu should be able to run on any RISC-V machine that > >conforms to the Priv-Spec. Note that the latest qemu model hasn't > >fully support a proper behavior of Priv-Spec 1.10 yet, but work > >around should be easy with very small fixes. Please check > >https://github.com/riscv/riscv-qemu/pull/115 for future updates. > > > >Cc: Nick Hu > >Cc: Greentime Hu > >Signed-off-by: Alan Kao > > We should really be able to detect PMU types at runtime (via a device tree > entry) rather than requiring that a single PMU is built in to the kernel. > This will require a handful of modifications to how this patch works, which > I'll try to list below. > >+menu "PMU type" > >+depends on PERF_EVENTS > >+ > >+config RISCV_BASE_PMU > >+bool "Base Performance Monitoring Unit" > >+def_bool y > >+help > >+ A base PMU that serves as a reference implementation and has limited > >+ feature of perf. > >+ > >+endmenu > >+ > > Rather than a menu where a single PMU can be selected, there should be > options to enable or disable support for each PMU type -- this is just like > how all our other drivers work. > I see. Sure. The descriptions and implementation will be refined in v3. > >+struct pmu * __weak __init riscv_init_platform_pmu(void) > >+{ > >+riscv_pmu = &riscv_base_pmu; > >+return riscv_pmu->pmu; > >+} > > Rather than relying on a weak symbol that gets overridden by other PMU > types, this should look through the device tree for a compatible PMU (in the > case of just the base PMU it could be any RISC-V hart) and install a PMU > handler for it. There'd probably be some sort of priority scheme here, like > there are for other driver subsystems, where we'd pick the best PMU driver > that's compatible with the PMUs on every hart. > > >+ > >+int __init init_hw_perf_events(void) > >+{ > >+struct pmu *pmu = riscv_init_platform_pmu(); > >+ > >+perf_irq = NULL; > >+perf_pmu_register(pmu, "cpu", PERF_TYPE_RAW); > >+return 0; > >+} > >+arch_initcall(init_hw_perf_events); > > Since we only have a single PMU type right now this isn't critical to handle > right away, but we will have to refactor this before adding another PMU. I see. My rough plan is to do the device tree parsing here, and if no specific PMU string is found then just register the base PMU proposed in this patch. How about this idea? Thanks.
[PATCH v2] riscv: Add support to no-FPU systems
This patch adds an option, CONFIG_FPU, to enable/disable floating procedures. Also, some style issues are fixed. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Zong Li --- arch/riscv/Kconfig | 9 arch/riscv/Makefile| 19 +++ arch/riscv/include/asm/switch_to.h | 6 +++ arch/riscv/kernel/entry.S | 3 +- arch/riscv/kernel/process.c| 7 ++- arch/riscv/kernel/signal.c | 82 +- 6 files changed, 90 insertions(+), 36 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 6debcc4afc72..6069597ba73f 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -232,6 +232,15 @@ config RISCV_BASE_PMU endmenu +config FPU + bool "FPU support" + default y + help + Say N here if you want to disable all floating-point related procedure + in the kernel. + + If you don't know what to do here, say Y. + endmenu menu "Kernel type" diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 6d4a5f6c3f4f..ad3033739430 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -26,7 +26,6 @@ ifeq ($(CONFIG_ARCH_RV64I),y) KBUILD_CFLAGS += -mabi=lp64 KBUILD_AFLAGS += -mabi=lp64 - KBUILD_MARCH = rv64im LDFLAGS += -melf64lriscv else BITS := 32 @@ -34,22 +33,20 @@ else KBUILD_CFLAGS += -mabi=ilp32 KBUILD_AFLAGS += -mabi=ilp32 - KBUILD_MARCH = rv32im LDFLAGS += -melf32lriscv endif KBUILD_CFLAGS += -Wall -ifeq ($(CONFIG_RISCV_ISA_A),y) - KBUILD_ARCH_A = a -endif -ifeq ($(CONFIG_RISCV_ISA_C),y) - KBUILD_ARCH_C = c -endif - -KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) +# ISA string setting +riscv-march-$(CONFIG_ARCH_RV32I) := rv32im +riscv-march-$(CONFIG_ARCH_RV64I) := rv64im +riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a +riscv-march-$(CONFIG_FPU) := $(riscv-march-y)fd +riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c +KBUILD_CFLAGS += -march=$(riscv-march-y) +KBUILD_AFLAGS += -march=$(riscv-march-y) -KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C) KBUILD_CFLAGS += -mno-save-restore KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET) diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index dd6b05bff75b..de333c012227 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -18,6 +18,7 @@ #include #include +#ifdef CONFIG_FPU extern void __fstate_save(struct task_struct *save_to); extern void __fstate_restore(struct task_struct *restore_from); @@ -54,6 +55,11 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_save(prev, regs); fstate_restore(next, task_pt_regs(next)); } +#else +#define fstate_save(task, regs) do { } while (0) +#define fstate_restore(task, regs) do { } while (0) +#define __switch_to_aux(__prev, __next) +#endif extern struct task_struct *__switch_to(struct task_struct *, struct task_struct *); diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 9aaf6c986771..89867c9aa4f5 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -357,6 +357,7 @@ ENTRY(__switch_to) ret ENDPROC(__switch_to) +#ifdef CONFIG_FPU ENTRY(__fstate_save) li a2, TASK_THREAD_F0 add a0, a0, a2 @@ -442,7 +443,7 @@ ENTRY(__fstate_restore) csrc sstatus, t1 ret ENDPROC(__fstate_restore) - +#endif .section ".rodata" /* Exception vector table */ diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index cb209139ba53..99d20283bb62 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -83,7 +83,12 @@ void show_regs(struct pt_regs *regs) void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - regs->sstatus = SR_SPIE /* User mode, irqs on */ | SR_FS_INITIAL; + /* User mode, irqs on */ +#ifdef CONFIG_FPU + regs->sstatus = SR_SPIE | SR_FS_INITIAL; +#else + regs->sstatus = SR_SPIE | SR_FS_OFF; +#endif regs->sepc = pc; regs->sp = sp; set_fs(USER_DS); diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 718d0c984ef0..a7a5ed5598a8 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,8 +37,9 @@ struct rt_sigframe { struct ucontext uc; }; -static long restore_d_state(struct pt_regs *regs, - struct __riscv_d_ext_state __user *state) +#ifdef CONFIG_FPU +static inline long __restore_d_state(struct pt_regs *regs, +struct __riscv_d_ext_state __user *state) { long err; err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state)); @@ -47,35 +48,7
Re: [PATCH v4 3/5] Cleanup ISA string setting
On Mon, Aug 20, 2018 at 03:22:55PM -0700, Palmer Dabbelt wrote: > On Tue, 07 Aug 2018 20:24:43 PDT (-0700), alan...@andestech.com wrote: > >Just a side note: (Assume that atomic and compressed is on) > > > >Before this patch, assembler was always given the riscv64imafdc > >MARCH string because there are fld/fsd's in entry.S; compiler was > >always given riscv64imac because kernel doesn't need floating point > >code generation. After this, the MARCH string in AFLAGS and CFLAGS > >become the same. > > > >Signed-off-by: Alan Kao > >Cc: Greentime Hu > >Cc: Vincent Chen > >Cc: Zong Li > >Cc: Nick Hu > >Reviewed-by: Christoph Hellwig > >--- > > arch/riscv/Makefile | 19 --- > > 1 file changed, 8 insertions(+), 11 deletions(-) > > > >diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile > >index 6d4a5f6c3f4f..e0fe6790624f 100644 > >--- a/arch/riscv/Makefile > >+++ b/arch/riscv/Makefile > >@@ -26,7 +26,6 @@ ifeq ($(CONFIG_ARCH_RV64I),y) > > > > KBUILD_CFLAGS += -mabi=lp64 > > KBUILD_AFLAGS += -mabi=lp64 > >-KBUILD_MARCH = rv64im > > LDFLAGS += -melf64lriscv > > else > > BITS := 32 > >@@ -34,22 +33,20 @@ else > > > > KBUILD_CFLAGS += -mabi=ilp32 > > KBUILD_AFLAGS += -mabi=ilp32 > >-KBUILD_MARCH = rv32im > > LDFLAGS += -melf32lriscv > > endif > > > > KBUILD_CFLAGS += -Wall > > > >-ifeq ($(CONFIG_RISCV_ISA_A),y) > >-KBUILD_ARCH_A = a > >-endif > >-ifeq ($(CONFIG_RISCV_ISA_C),y) > >-KBUILD_ARCH_C = c > >-endif > >- > >-KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) > >+# ISA string setting > >+riscv-march-$(CONFIG_ARCH_RV32I):= rv32im > >+riscv-march-$(CONFIG_ARCH_RV64I):= rv64im > >+riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a > >+riscv-march-y := $(riscv-march-y)fd > >+riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c > >+KBUILD_CFLAGS += -march=$(riscv-march-y) > >+KBUILD_AFLAGS += -march=$(riscv-march-y) > > > >-KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C) > > We used to have "fd" disabled in KBUILD_CFLAGS because we wanted to ensure > that any use of floating-point types within the kernel would trigger the > inclusion of soft-float libraries rather than emitting hardware > floating-point instructions. The worry here is that we'd end up corrupting > the user's floating-point state with the kernel accesses because of the lazy > save/restore stuff going on. Thanks for pointing that out. Just as you said, the use of KBUILD_CFLAGS=*fd* is based on the assumption that not a single floating-point instruction involves in the kernel, and that might be wrong. > I remember at some point it was illegal to use floating-point within the > kernel, but for some reason I thought that had changed. I do see a handful > of references to "float" and "double" in the kernel source, and most of > references to kernel_fpu_begin() appear to be in SSE-specific stuff. My one > worry are the usages in drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c, as > I can't quickly demonstrate they won't happen. Empirically, this CFLAGS with *fd* did not cause any trouble to me, but of course this is not a good statement to support this patch. Meanwhile, I find a flaw in "[PATCH 4/5] Allow to Disable FPU Support." The purpose of this "[PATCH 3/5] Cleanup ISA String" was to make CONFIG_FPU a switch for the appearance of "fd" in both KBUILD_CFLAGS and KBUILD_ASFLAGS, but somehow the modification was forgotten. > > If we do this I think we should at least ensure kernel_fpu_{begin,end}() do > the right thing for RISC-V. I'd still feel safer telling the C compiler to > disallow floating-point, though, as I'm a bit paranoid that GCC might go and > emit a floating-point instruction even when it's not explicitly asked for. > I just asked Jim, who actually understands GCC, and he said that it'll spill > to floating-point registers if the cost function determines it's cheaper > than the stack. While he thinks that's unlikely, I don't really want to > rely a GCC cost function for the correctness of our kernel port. The purpose of this whole patchset was to remove all floating-point-related logic in kernel space (while remainging FPU systems work as usual), so implementing the two APIs would be out of scope here. I suggest that, some people have to provide these APIs if they do need hardware floating-point calculation in kernel space (kernel
[PATCH v8 0/5] riscv: Add support to no-FPU systems
This patchset adds an option, CONFIG_FPU, to enable/disable floating- point procedures. Kernel's new behavior will be as follows: * with CONFIG_FPU=y All FPU codes are reserved. If no FPU is found during booting, a global flag will be set, and those functions will be bypassed with condition check to that flag. * with CONFIG_FPU=n No floating-point instructions in kernel and all related settings are excluded. Changes in v8: - Fix a build fail introduced in v7. Changes in v7: - Remove "fd" attribute from KBUILD_CFLAGS. Changes in v6 (PATCH 0005 only): - Make the flag checking neater. Changes in v5: - Invert the polarity of checking flag from no_fpu to has_fpu. Changes in v4: - Append a new patch to detect existence of FPU and followups. - Add SPDX header to newly created fpu.S. - Fix a build error, sorry for that. - Fix wording, style, etc. Changes in v3: - Refactor the whole patch into independent ones. Changes in v2: - Various code cleanups and style fixes. Alan Kao (5): Extract FPU context operations from entry.S Refactor FPU code in signal setup/return procedures Cleanup ISA string setting Allow to disable FPU support Auto-detect whether a FPU exists arch/riscv/Kconfig | 9 arch/riscv/Makefile| 19 +++ arch/riscv/include/asm/switch_to.h | 12 - arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/cpufeature.c | 8 +++ arch/riscv/kernel/entry.S | 87 -- arch/riscv/kernel/fpu.S| 106 + arch/riscv/kernel/process.c| 6 ++- arch/riscv/kernel/signal.c | 75 -- 9 files changed, 196 insertions(+), 127 deletions(-) create mode 100644 arch/riscv/kernel/fpu.S -- 2.7.4
[PATCH v8 4/5] Allow to disable FPU support
FPU codes have been separated from common part in previous patches. This patch add the CONFIG_FPU option and some stubs, so that a no-FPU configuration is allowed. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/Kconfig | 9 + arch/riscv/Makefile| 2 +- arch/riscv/include/asm/switch_to.h | 10 ++ arch/riscv/kernel/Makefile | 2 +- arch/riscv/kernel/process.c| 4 +++- arch/riscv/kernel/signal.c | 5 + 6 files changed, 29 insertions(+), 3 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index a344980..a63f9db 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -208,6 +208,15 @@ config RISCV_BASE_PMU endmenu +config FPU + bool "FPU support" + default y + help + Say N here if you want to disable all floating-point related procedure + in the kernel. + + If you don't know what to do here, say Y. + endmenu menu "Kernel type" diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 01393e1..901770f 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -44,7 +44,7 @@ KBUILD_CFLAGS += -Wall riscv-march-$(CONFIG_ARCH_RV32I) := rv32im riscv-march-$(CONFIG_ARCH_RV64I) := rv64im riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a -riscv-march-y := $(riscv-march-y)fd +riscv-march-$(CONFIG_FPU) := $(riscv-march-y)fd riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y)) KBUILD_AFLAGS += -march=$(riscv-march-y) diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index dd6b05b..093050b 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -18,6 +18,7 @@ #include #include +#ifdef CONFIG_FPU extern void __fstate_save(struct task_struct *save_to); extern void __fstate_restore(struct task_struct *restore_from); @@ -55,6 +56,15 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_restore(next, task_pt_regs(next)); } +#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) + +#else +#define fstate_save(task, regs) do { } while (0) +#define fstate_restore(task, regs) do { } while (0) +#define __switch_to_aux(__prev, __next) do { } while (0) +#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_OFF) +#endif + extern struct task_struct *__switch_to(struct task_struct *, struct task_struct *); diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index bd433efd..f13f7f2 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -13,7 +13,6 @@ extra-y += vmlinux.lds obj-y += cpu.o obj-y += cpufeature.o obj-y += entry.o -obj-y += fpu.o obj-y += irq.o obj-y += process.o obj-y += ptrace.o @@ -32,6 +31,7 @@ obj-y += vdso/ CFLAGS_setup.o := -mcmodel=medany +obj-$(CONFIG_FPU) += fpu.o obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index d7c6ca7..07d5156 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -76,7 +76,7 @@ void show_regs(struct pt_regs *regs) void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - regs->sstatus = SR_SPIE /* User mode, irqs on */ | SR_FS_INITIAL; + regs->sstatus = DEFAULT_SSTATUS; regs->sepc = pc; regs->sp = sp; set_fs(USER_DS); @@ -84,12 +84,14 @@ void start_thread(struct pt_regs *regs, unsigned long pc, void flush_thread(void) { +#ifdef CONFIG_FPU /* * Reset FPU context * frm: round to nearest, ties to even (IEEE default) * fflags: accrued exceptions cleared */ memset(¤t->thread.fstate, 0, sizeof(current->thread.fstate)); +#endif } int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 6a18b98..2450b82 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,6 +37,7 @@ struct rt_sigframe { struct ucontext uc; }; +#ifdef CONFIG_FPU static long restore_fp_state(struct pt_regs *regs, union __riscv_fp_state *sc_fpregs) { @@ -85,6 +86,10 @@ static long save_fp_state(struct pt_regs *regs, return err; } +#else +#define save_fp_state(task, regs) (0) +#define restore_fp_state(task, regs) (0) +#endif static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) -- 2.7.4
[PATCH v8 2/5] Refactor FPU code in signal setup/return procedures
FPU-related logic is separated from normal signal handling path in this patch. Kernel can easily be configured to exclude those procedures for no-FPU systems. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/kernel/signal.c | 68 -- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 718d0c9..6a18b98 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -37,45 +37,63 @@ struct rt_sigframe { struct ucontext uc; }; -static long restore_d_state(struct pt_regs *regs, - struct __riscv_d_ext_state __user *state) +static long restore_fp_state(struct pt_regs *regs, +union __riscv_fp_state *sc_fpregs) { long err; + struct __riscv_d_ext_state __user *state = &sc_fpregs->d; + size_t i; + err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state)); - if (likely(!err)) - fstate_restore(current, regs); + if (unlikely(err)) + return err; + + fstate_restore(current, regs); + + /* We support no other extension state at this time. */ + for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { + u32 value; + + err = __get_user(value, &sc_fpregs->q.reserved[i]); + if (unlikely(err)) + break; + if (value != 0) + return -EINVAL; + } + return err; } -static long save_d_state(struct pt_regs *regs, - struct __riscv_d_ext_state __user *state) +static long save_fp_state(struct pt_regs *regs, + union __riscv_fp_state *sc_fpregs) { + long err; + struct __riscv_d_ext_state __user *state = &sc_fpregs->d; + size_t i; + fstate_save(current, regs); - return __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); + err = __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); + if (unlikely(err)) + return err; + + /* We support no other extension state at this time. */ + for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { + err = __put_user(0, &sc_fpregs->q.reserved[i]); + if (unlikely(err)) + break; + } + + return err; } static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { long err; - size_t i; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); - if (unlikely(err)) - return err; /* Restore the floating-point state. */ - err = restore_d_state(regs, &sc->sc_fpregs.d); - if (unlikely(err)) - return err; - /* We support no other extension state at this time. */ - for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) { - u32 value; - err = __get_user(value, &sc->sc_fpregs.q.reserved[i]); - if (unlikely(err)) - break; - if (value != 0) - return -EINVAL; - } + err |= restore_fp_state(regs, &sc->sc_fpregs); return err; } @@ -124,14 +142,10 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, { struct sigcontext __user *sc = &frame->uc.uc_mcontext; long err; - size_t i; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); /* Save the floating-point state. */ - err |= save_d_state(regs, &sc->sc_fpregs.d); - /* We support no other extension state at this time. */ - for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) - err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]); + err |= save_fp_state(regs, &sc->sc_fpregs); return err; } -- 2.7.4
[PATCH v8 5/5] Auto-detect whether a FPU exists
We expect that a kernel with CONFIG_FPU=y can still support no-FPU machines. To do so, the kernel should first examine the existence of a FPU, then do nothing if a FPU does exist; otherwise, it should disable/bypass all FPU-related functions. In this patch, a new global variable, has_fpu, is created and determined when parsing the hardware capability from device tree during booting. This variable is used in those FPU-related functions. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/include/asm/switch_to.h | 8 arch/riscv/kernel/cpufeature.c | 8 arch/riscv/kernel/process.c| 4 +++- arch/riscv/kernel/signal.c | 6 -- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index 093050b..7335590 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -56,13 +56,12 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_restore(next, task_pt_regs(next)); } -#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_INITIAL) - +extern bool has_fpu; #else +#define has_fpu false #define fstate_save(task, regs) do { } while (0) #define fstate_restore(task, regs) do { } while (0) #define __switch_to_aux(__prev, __next) do { } while (0) -#define DEFAULT_SSTATUS (SR_SPIE | SR_FS_OFF) #endif extern struct task_struct *__switch_to(struct task_struct *, @@ -72,7 +71,8 @@ extern struct task_struct *__switch_to(struct task_struct *, do { \ struct task_struct *__prev = (prev);\ struct task_struct *__next = (next);\ - __switch_to_aux(__prev, __next);\ + if (has_fpu)\ + __switch_to_aux(__prev, __next);\ ((last) = __switch_to(__prev, __next)); \ } while (0) diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 17011a8..46942e6 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -22,6 +22,9 @@ #include unsigned long elf_hwcap __read_mostly; +#ifdef CONFIG_FPU +bool has_fpu __read_mostly; +#endif void riscv_fill_hwcap(void) { @@ -58,4 +61,9 @@ void riscv_fill_hwcap(void) elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; pr_info("elf_hwcap is 0x%lx", elf_hwcap); + +#ifdef CONFIG_FPU + if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)) + has_fpu = true; +#endif } diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 07d5156..bef1999 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -76,7 +76,9 @@ void show_regs(struct pt_regs *regs) void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - regs->sstatus = DEFAULT_SSTATUS; + regs->sstatus = SR_SPIE; + if (has_fpu) + regs->sstatus |= SR_FS_INITIAL; regs->sepc = pc; regs->sp = sp; set_fs(USER_DS); diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 2450b82..f9b5e7e 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -98,7 +98,8 @@ static long restore_sigcontext(struct pt_regs *regs, /* sc_regs is structured the same as the start of pt_regs */ err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); /* Restore the floating-point state. */ - err |= restore_fp_state(regs, &sc->sc_fpregs); + if (has_fpu) + err |= restore_fp_state(regs, &sc->sc_fpregs); return err; } @@ -150,7 +151,8 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); /* Save the floating-point state. */ - err |= save_fp_state(regs, &sc->sc_fpregs); + if (has_fpu) + err |= save_fp_state(regs, &sc->sc_fpregs); return err; } -- 2.7.4
[PATCH v8 1/5] Extract FPU context operations from entry.S
We move __fstate_save and __fstate_restore to a new source file, fpu.S. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu Reviewed-by: Christoph Hellwig --- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/entry.S | 87 - arch/riscv/kernel/fpu.S| 106 + 3 files changed, 107 insertions(+), 87 deletions(-) create mode 100644 arch/riscv/kernel/fpu.S diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index e1274fc..bd433efd 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -13,6 +13,7 @@ extra-y += vmlinux.lds obj-y += cpu.o obj-y += cpufeature.o obj-y += entry.o +obj-y += fpu.o obj-y += irq.o obj-y += process.o obj-y += ptrace.o diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index fa2c08e..59c02e2 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -357,93 +357,6 @@ ENTRY(__switch_to) ret ENDPROC(__switch_to) -ENTRY(__fstate_save) - li a2, TASK_THREAD_F0 - add a0, a0, a2 - li t1, SR_FS - csrs sstatus, t1 - frcsr t0 - fsd f0, TASK_THREAD_F0_F0(a0) - fsd f1, TASK_THREAD_F1_F0(a0) - fsd f2, TASK_THREAD_F2_F0(a0) - fsd f3, TASK_THREAD_F3_F0(a0) - fsd f4, TASK_THREAD_F4_F0(a0) - fsd f5, TASK_THREAD_F5_F0(a0) - fsd f6, TASK_THREAD_F6_F0(a0) - fsd f7, TASK_THREAD_F7_F0(a0) - fsd f8, TASK_THREAD_F8_F0(a0) - fsd f9, TASK_THREAD_F9_F0(a0) - fsd f10, TASK_THREAD_F10_F0(a0) - fsd f11, TASK_THREAD_F11_F0(a0) - fsd f12, TASK_THREAD_F12_F0(a0) - fsd f13, TASK_THREAD_F13_F0(a0) - fsd f14, TASK_THREAD_F14_F0(a0) - fsd f15, TASK_THREAD_F15_F0(a0) - fsd f16, TASK_THREAD_F16_F0(a0) - fsd f17, TASK_THREAD_F17_F0(a0) - fsd f18, TASK_THREAD_F18_F0(a0) - fsd f19, TASK_THREAD_F19_F0(a0) - fsd f20, TASK_THREAD_F20_F0(a0) - fsd f21, TASK_THREAD_F21_F0(a0) - fsd f22, TASK_THREAD_F22_F0(a0) - fsd f23, TASK_THREAD_F23_F0(a0) - fsd f24, TASK_THREAD_F24_F0(a0) - fsd f25, TASK_THREAD_F25_F0(a0) - fsd f26, TASK_THREAD_F26_F0(a0) - fsd f27, TASK_THREAD_F27_F0(a0) - fsd f28, TASK_THREAD_F28_F0(a0) - fsd f29, TASK_THREAD_F29_F0(a0) - fsd f30, TASK_THREAD_F30_F0(a0) - fsd f31, TASK_THREAD_F31_F0(a0) - sw t0, TASK_THREAD_FCSR_F0(a0) - csrc sstatus, t1 - ret -ENDPROC(__fstate_save) - -ENTRY(__fstate_restore) - li a2, TASK_THREAD_F0 - add a0, a0, a2 - li t1, SR_FS - lw t0, TASK_THREAD_FCSR_F0(a0) - csrs sstatus, t1 - fld f0, TASK_THREAD_F0_F0(a0) - fld f1, TASK_THREAD_F1_F0(a0) - fld f2, TASK_THREAD_F2_F0(a0) - fld f3, TASK_THREAD_F3_F0(a0) - fld f4, TASK_THREAD_F4_F0(a0) - fld f5, TASK_THREAD_F5_F0(a0) - fld f6, TASK_THREAD_F6_F0(a0) - fld f7, TASK_THREAD_F7_F0(a0) - fld f8, TASK_THREAD_F8_F0(a0) - fld f9, TASK_THREAD_F9_F0(a0) - fld f10, TASK_THREAD_F10_F0(a0) - fld f11, TASK_THREAD_F11_F0(a0) - fld f12, TASK_THREAD_F12_F0(a0) - fld f13, TASK_THREAD_F13_F0(a0) - fld f14, TASK_THREAD_F14_F0(a0) - fld f15, TASK_THREAD_F15_F0(a0) - fld f16, TASK_THREAD_F16_F0(a0) - fld f17, TASK_THREAD_F17_F0(a0) - fld f18, TASK_THREAD_F18_F0(a0) - fld f19, TASK_THREAD_F19_F0(a0) - fld f20, TASK_THREAD_F20_F0(a0) - fld f21, TASK_THREAD_F21_F0(a0) - fld f22, TASK_THREAD_F22_F0(a0) - fld f23, TASK_THREAD_F23_F0(a0) - fld f24, TASK_THREAD_F24_F0(a0) - fld f25, TASK_THREAD_F25_F0(a0) - fld f26, TASK_THREAD_F26_F0(a0) - fld f27, TASK_THREAD_F27_F0(a0) - fld f28, TASK_THREAD_F28_F0(a0) - fld f29, TASK_THREAD_F29_F0(a0) - fld f30, TASK_THREAD_F30_F0(a0) - fld f31, TASK_THREAD_F31_F0(a0) - fscsr t0 - csrc sstatus, t1 - ret -ENDPROC(__fstate_restore) - - .section ".rodata" /* Exception vector table */ ENTRY(excp_vect_table) diff --git a/arch/riscv/kernel/fpu.S b/arch/riscv/kernel/fpu.S new file mode 100644 index 000..1defb06 --- /dev/null +++ b/arch/riscv/kernel/fpu.S @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2012 Regents of the University of California + * Copyright (C) 2017 SiFive + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include
[PATCH v8 3/5] Cleanup ISA string setting
This patch cleanup the MARCH string passing to both compiler and assembler. Note that the CFLAGS should not contain "fd" before we have mechnisms like kernel_fpu_begin/end in other architectures. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen Cc: Zong Li Cc: Nick Hu --- arch/riscv/Makefile | 19 --- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 61ec424..01393e1 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -28,7 +28,6 @@ ifeq ($(CONFIG_ARCH_RV64I),y) KBUILD_CFLAGS += $(call cc-ifversion, -ge, 0500, -DCONFIG_ARCH_SUPPORTS_INT128) - KBUILD_MARCH = rv64im KBUILD_LDFLAGS += -melf64lriscv else BITS := 32 @@ -36,22 +35,20 @@ else KBUILD_CFLAGS += -mabi=ilp32 KBUILD_AFLAGS += -mabi=ilp32 - KBUILD_MARCH = rv32im KBUILD_LDFLAGS += -melf32lriscv endif KBUILD_CFLAGS += -Wall -ifeq ($(CONFIG_RISCV_ISA_A),y) - KBUILD_ARCH_A = a -endif -ifeq ($(CONFIG_RISCV_ISA_C),y) - KBUILD_ARCH_C = c -endif - -KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) +# ISA string setting +riscv-march-$(CONFIG_ARCH_RV32I) := rv32im +riscv-march-$(CONFIG_ARCH_RV64I) := rv64im +riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a +riscv-march-y := $(riscv-march-y)fd +riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c +KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y)) +KBUILD_AFLAGS += -march=$(riscv-march-y) -KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C) KBUILD_CFLAGS += -mno-save-restore KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET) -- 2.7.4
Re: [RFC 0/2] RISC-V: A proposal to add vendor-specific code
On Wed, Oct 31, 2018 at 07:17:45AM -0700, Christoph Hellwig wrote: > On Wed, Oct 31, 2018 at 04:46:10PM +0530, Anup Patel wrote: > > I agree that we need a place for vendor-specific ISA extensions and > > having vendor-specific directories is also good. > > The only sensible answer is that we should not allow vendor specific > extensions in the kernel at all. ... How can this even be possible if a extension includes an extra register set as some domain-specific context? In such a case, kernel should at least process the context during any context switch, just like how it deals with the FP context. > ... We need to standardize cache flushing > and we need to do it soon and not introduce horrible bandaids because > the foundation did not do its work. > > ___ > linux-riscv mailing list > linux-ri...@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-riscv
Re: [PATCH v8 3/5] Cleanup ISA string setting
Hi Guenter, On Sat, Oct 13, 2018 at 05:02:05PM -0700, Guenter Roeck wrote: > Hi, > > With this patch in -next applied, I get the following error > when building riscv:defconfig. I guess what you meant was this commit: commit 0a5bee05fc67ce2044b8d91a18abbf14042da531 The modification in Makefile was -endif - -KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) +# ISA string setting +riscv-march-$(CONFIG_ARCH_RV32I) := rv32im +riscv-march-$(CONFIG_ARCH_RV64I) := rv64im +riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a +riscv-march-y := fd +riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c and the ":= fd" line was wrong. It should have been +riscv-march-y := $(riscv-march-y)fd > > > What am I missing ? Does RISC-V now require a new non-upstream compiler ? > Or a special version of make ? I am currently using GNU Make 4.1. So I sent the v8 to fix this problem. Sorry for the inconvinience. > > Thanks, > Guenter > > --- And Palmer, it seems that the patch that causes this build error has been pulled into linux-next. Any idea how to fix that one? Many thanks, Alan
Re: [PATCH v7 0/5] riscv: Add support to no-FPU systems
On Thu, Sep 06, 2018 at 02:45:04AM -0700, Palmer Dabbelt wrote: > On Sun, 26 Aug 2018 18:07:50 PDT (-0700), alan...@andestech.com wrote: > >This patchset adds an option, CONFIG_FPU, to enable/disable floating- > >point procedures. > > > >Kernel's new behavior will be as follows: > > > >* with CONFIG_FPU=y > > All FPU codes are reserved. If no FPU is found during booting, a > > global flag will be set, and those functions will be bypassed with > > condition check to that flag. > > > >* with CONFIG_FPU=n > > No floating-point instructions in kernel and all related settings > > are excluded. > > > >Changes in v7: > > - Remove "fd" attribute from KBUILD_CFLAGS. > > > >Changes in v6 (PATCH 0005 only): > > - Make the flag checking neater. > > > >Changes in v5: > > - Invert the polarity of checking flag from no_fpu to has_fpu. > > > >Changes in v4: > > - Append a new patch to detect existence of FPU and followups. > > - Add SPDX header to newly created fpu.S. > > - Fix a build error, sorry for that. > > - Fix wording, style, etc. > > > >Changes in v3: > > - Refactor the whole patch into independent ones. > > > >Changes in v2: > > - Various code cleanups and style fixes. > > > > > >Alan Kao (5): > > Extract FPU context operations from entry.S > > Refactor FPU code in signal setup/return procedures > > Cleanup ISA string setting > > Allow to disable FPU support > > Auto-detect whether a FPU exists > > > > arch/riscv/Kconfig | 9 +++ > > arch/riscv/Makefile| 19 +++--- > > arch/riscv/include/asm/switch_to.h | 12 +++- > > arch/riscv/kernel/Makefile | 1 + > > arch/riscv/kernel/cpufeature.c | 8 +++ > > arch/riscv/kernel/entry.S | 87 --- > > arch/riscv/kernel/fpu.S| 106 + > > arch/riscv/kernel/process.c| 6 +- > > arch/riscv/kernel/signal.c | 75 > > 9 files changed, 196 insertions(+), 127 deletions(-) > > create mode 100644 arch/riscv/kernel/fpu.S > > Thanks! I'll add this to our for-next branch. Any updates?
Re: [RFC 0/2] RISC-V: A proposal to add vendor-specific code
On Thu, Nov 01, 2018 at 10:50:04AM -0700, Palmer Dabbelt wrote: > On Wed, 31 Oct 2018 17:55:42 PDT (-0700), alan...@andestech.com wrote: > >On Wed, Oct 31, 2018 at 07:17:45AM -0700, Christoph Hellwig wrote: > >>On Wed, Oct 31, 2018 at 04:46:10PM +0530, Anup Patel wrote: > >>> I agree that we need a place for vendor-specific ISA extensions and > >>> having vendor-specific directories is also good. > >> > >>The only sensible answer is that we should not allow vendor specific > >>extensions in the kernel at all. ... > > > >How can this even be possible if a extension includes an extra register > >set as some domain-specific context? In such a case, kernel should > >at least process the context during any context switch, just like how it > >deals with the FP context. > > Ya, I think there are cases where vendor-specific extensions are going to be > necessary to handle within the kernel. Right now the only one I can think > of is the performance counter stuff, where we explicitly allow > vendor-specific counters as part of the ISA spec. > > For stateful extensions, we currently have a standard mechanism where the XS > bits get set in sstatus and the actual save/restore code is hidden behind an > SBI call. That call doesn't currently exist, but if we just go ahead and > add one it should be easy to support this from within Linux. We'll need to > figure out how to enable these custom extensions from userspace, but that > seems tractable as well. We'll probably also want some fast-path for the V > extension (and any other stateful standard extensions), but I think as long > as the V extension adds a quick check for dirtiness then it's not a big > deal. > > Do you guys have stateful extensions? We're trying really hard to avoid > them at SiFive because they're a huge headache, so unless there's a > compelling base of software using one I don't want to go add support if we > can avoid it. Currently no, but the future is hard to see. As long as the extensible freedom claimed by the RISC-V foundation remains true, such extensions may have their role to play. Don't worry now, I was just to give a example that in some possible vendor-specific cases the kernel cannot keep itself from involving.
Re: ftrace: Proposal for an Alternative RecordMcount framework
On Wed, Feb 28, 2018 at 05:12:52AM +0800, Steven Rostedt wrote: > On Tue, 27 Feb 2018 18:04:26 +0800 > Alan Kao wrote: > > > 1. During the final linking stages, do "objdump vmlinux.o | grep ..." [2] > > Note, doing it at that stage takes the longest time. It makes small > changes much longer to compile. That said... > What if we can have some option to *disable* all the recordmcount.pl lauches after every .o? There will be only an oneshot grep for a near-complete vmlinux binary. > > 2. Form the output as an ELF objecj > > 3. Link the object to __mcount_loc_start symbol > > 4. Done > > > > With the similar reason as the patch [3], we should mark _mcount to be > > a weak symbol to prevent it from being relaxed later. > > > > We would like to know your opinion and comments on this. > > Thanks! > > What about just having your arch use recordmcount.c instead? It doesn't > do any grepping. It is an elf reader and modifier and modifies the .o > file directly. Thanks for the hint. But after a quick scan, it seems that recordmcount.c processes .o files in a per-file basis, which means that we will still suffer from the linker relaxation problem. > > Note, I will be rewriting that code in the near future too, to > consolidate it with objtool. > > -- Steve Please allow me to state the problem more clearly here. I hope this helps. 1. locations of mcount are recorded in a per-file basis. 2. to optimize the binary, the linker turns on some aggressive options, including relaxation. 3. the optimizations changes the original offset. 4. already recorded mcount call-sites no longer point to their real positions. 5. still a linked vmlinux is made. 6. dynamic ftrace breaks the real logic in the kernel space, panics happen. Thanks, Alan
Re: [PATCH 0/2] perf: riscv: Preliminary Perf Event Support on RISC-V
On Tue, Apr 03, 2018 at 03:45:17PM -0700, Palmer Dabbelt wrote: > On Tue, 03 Apr 2018 07:29:02 PDT (-0700), alan...@andestech.com wrote: > >On Mon, Apr 02, 2018 at 08:15:44PM -0700, Palmer Dabbelt wrote: > >>On Mon, 02 Apr 2018 05:31:22 PDT (-0700), alan...@andestech.com wrote: > >>>This implements the baseline PMU for RISC-V platforms. > >>> > >>>To ease future PMU portings, a guide is also written, containing > >>>perf concepts, arch porting practices and some hints. > >>> > >>>Changes in v2: > >>> - Fix the bug reported by Alex, which was caused by not sufficient > >>> initialization. Check https://lkml.org/lkml/2018/3/31/251 for the > >>> discussion. > >>> > >>>Alan Kao (2): > >>> perf: riscv: preliminary RISC-V support > >>> perf: riscv: Add Document for Future Porting Guide > >>> > >>> Documentation/riscv/pmu.txt | 249 +++ > >>> arch/riscv/Kconfig | 12 + > >>> arch/riscv/include/asm/perf_event.h | 76 +- > >>> arch/riscv/kernel/Makefile | 1 + > >>> arch/riscv/kernel/perf_event.c | 468 > >>> > >>> 5 files changed, 802 insertions(+), 4 deletions(-) > >>> create mode 100644 Documentation/riscv/pmu.txt > >>> create mode 100644 arch/riscv/kernel/perf_event.c > >> > >>I'm having some trouble pulling this into my tree. I think you might have > >>another patch floating around somewhere, as I don't have any > >>arch/riscv/include/asm/perf_event.h right now. > >> > >>Do you mind rebasing this on top of linux-4.16 so I can look properly? > >> > >>Thanks! > > > >Sorry for the inconvenience, but this patch was based on Alex's patch at > >https://github.com/riscv/riscv-linux/pull/124/files. I thought that one > >had already been picked into your tree. > > > >Any ideas? > > Thanks, it applies on top of that. I'm going to play around with this a > bit, but it looks generally good. Note that to make it work better when wraparound occurs, you should change the value of *.counter_width* into the width of real hardware counters. This is because this patch does not handle wraparound checking, so using a wider bit mask may sometimes report a extremely large number. Ideally this should be done by adding a Kconfig option called "Hifive Unleashed PMU" which automatically sets the width an reuses most of the baseline codes. What do you think about this? Thanks.
Re: [PATCH v2 2/2] perf: riscv: Add Document for Future Porting Guide
Hi Alex, On Tue, Apr 03, 2018 at 07:08:43PM -0700, Alex Solomatnikov wrote: > Doc fixes: > > Thanks for these fixes. I'll edit this patch and send a v3 once I am done with the PMU patch. I suppose a "Reviewed-by: Alex Solomatnikov" appending at the end of the commit will be great, right? Alan > diff --git a/Documentation/riscv/pmu.txt b/Documentation/riscv/pmu.txt > index a3e930e..ae90a5e 100644 > --- a/Documentation/riscv/pmu.txt > +++ b/Documentation/riscv/pmu.txt > @@ -20,7 +20,7 @@ the lack of the following general architectural > performance monitoring features: > * Enabling/Disabling counters >Counters are just free-running all the time in our case. > * Interrupt caused by counter overflow > - No such design in the spec. > + No such feature in the spec. > * Interrupt indicator >It is not possible to have many interrupt ports for all counters, so an >interrupt indicator is required for software to tell which counter has > @@ -159,14 +159,14 @@ interrupt for perf, so the details are to be > completed in the future. > > They seem symmetric but perf treats them quite differently. For reading, > there > is a *read* interface in *struct pmu*, but it serves more than just reading. > -According to the context, the *read* function not only read the content of > the > -counter (event->count), but also update the left period to the next interrupt > +According to the context, the *read* function not only reads the content of > the > +counter (event->count), but also updates the left period for the next > interrupt > (event->hw.period_left). > > But the core of perf does not need direct write to counters. Writing > counters > -hides behind the abstraction of 1) *pmu->start*, literally start > counting so one > +is hidden behind the abstraction of 1) *pmu->start*, literally start > counting so one > has to set the counter to a good value for the next interrupt; 2) > inside the IRQ > -it should set the counter with the same reason. > +it should set the counter to the same reasonable value. > > Reading is not a problem in RISC-V but writing would need some effort, since > counters are not allowed to be written by S-mode. > @@ -190,37 +190,37 @@ Three states (event->hw.state) are defined: > A normal flow of these state transitions are as follows: > > * A user launches a perf event, resulting in calling to *event_init*. > -* When being context-switched in, *add* is called by the perf core, with flag > - PERF_EF_START, which mean that the event should be started after it is > added. > - In this stage, an general event is binded to a physical counter, if any. > +* When being context-switched in, *add* is called by the perf core, with a > flag > + PERF_EF_START, which means that the event should be started after > it is added. > + At this stage, a general event is bound to a physical counter, if any. >The state changes to PERF_HES_STOPPED and PERF_HES_UPTODATE, > because it is now >stopped, and the (software) event count does not need updating. > ** *start* is then called, and the counter is enabled. > - With flag PERF_EF_RELOAD, it write the counter to an appropriate > value (check > - previous section for detail). > - No writing is made if the flag does not contain PERF_EF_RELOAD. > - The state now is reset to none, because it is neither stopped nor update > - (the counting already starts) > -* When being context-switched out, *del* is called. It then checkout all the > - events in the PMU and call *stop* to update their counts. > + With flag PERF_EF_RELOAD, it writes an appropriate value to the > counter (check > + the previous section for details). > + Nothing is written if the flag does not contain PERF_EF_RELOAD. > + The state now is reset to none, because it is neither stopped nor updated > + (the counting already started) > +* When being context-switched out, *del* is called. It then checks out all > the > + events in the PMU and calls *stop* to update their counts. > ** *stop* is called by *del* > and the perf core with flag PERF_EF_UPDATE, and it often shares the same > subroutine as *read* with the same logic. > The state changes to PERF_HES_STOPPED and PERF_HES_UPTODATE, again. > > -** Life cycles of these two pairs: *add* and *del* are called repeatedly as > +** Life cycle of these two pairs: *add* and *del* are called repeatedly as >tasks switch in-and-out; *start* and *stop* is also called when the perf > core >needs a quick stop-and-start, for instance, when the interrupt > period is being >adjusted. > > -Current implementation is sufficient for now and can be easily extend to > +Current implementation is sufficient for now and can be easily > extended with new > features in the future. > > A. Related Structures > - > > -* struct pmu: include/linux/perf_events.h > -* struct riscv_pmu: arch/riscv/include/asm/perf_events.h > +* struct pmu: include/linux/perf_event.h > +* s
Re: [PATCH 1/2] perf: riscv: preliminary RISC-V support
Hi Alex, I'm appreciated for your reply and tests. On Wed, Mar 28, 2018 at 03:58:41PM -0700, Alex Solomatnikov wrote: > Did you test this code? I did test this patch on QEMU's virt model with multi-hart, which is the only RISC-V machine I have for now. But as I mentioned in https://github.com/riscv/riscv-qemu/pull/115 , the hardware counter support in QEMU is not fully conformed to the 1.10 Priv-Spec, so I had to slightly tweak the code to make reading work. Specifically, the read to cycle and instret in QEMU looks like this: ... case CSR_INSTRET: case CSR_CYCLE: // if (ctr_ok) { return cpu_get_host_ticks(); // } break; ... and the two lines of comment was the tweak. On such environment, I did not get anything unexpected. No matter which of them is requested, QEMU returns the host's tick. > > I got funny numbers when I tried to run it on HiFive Unleashed: > > perf stat mem-latency > ... > > Performance counter stats for 'mem-latency': > > 157.907000 task-clock (msec) #0.940 CPUs utilized > > 1 context-switches #0.006 K/sec > > 1 cpu-migrations#0.006 K/sec > > 4102 page-faults #0.026 M/sec > > 157923752 cycles#1.000 GHz > > 9223372034948899840 instructions # 58403957087.78 insn > per cycle > branches > > branch-misses > > >0.168046000 seconds time elapsed > > > Tracing read_counter(), I see this: > > Jan 1 00:41:50 buildroot user.info kernel: [ 2510.058809] CPU 3: > read_counter idx=0 val=2528358954912 > Jan 1 00:41:50 buildroot user.info kernel: [ 2510.063339] CPU 3: > read_counter idx=1 val=53892244920 > Jan 1 00:41:50 buildroot user.info kernel: [ 2510.118160] CPU 3: > read_counter idx=0 val=2528418303035 > Jan 1 00:41:50 buildroot user.info kernel: [ 2510.122694] CPU 3: > read_counter idx=1 val=53906699665 > Jan 1 00:41:50 buildroot user.info kernel: [ 2510.216736] CPU 1: > read_counter idx=0 val=2528516878664 > Jan 1 00:41:50 buildroot user.info kernel: [ 2510.221270] CPU 1: > read_counter idx=1 val=51986369142 > > It looks like the counter values from different cores are subtracted and > wraparound occurs. > Thanks for the hint. It makes sense. 9223372034948899840 is 7fff8e66a400, which should be a wraparound with the mask I set (63-bit) in the code. I will try this direction. Ideally, we can solve it by explicitly syncing the hwc->prev_count when a cpu migration event happens. > > Also, core IDs and socket IDs are wrong in perf report: > As Palmer has replied to this, I have no comment here. > perf report --header -I > Error: > The perf.data file has no samples! > # > # captured on: Thu Jan 1 02:52:07 1970 > # hostname : buildroot > # os release : 4.15.0-00045-g0d7c030-dirty > # perf version : 4.15.0 > # arch : riscv64 > # nrcpus online : 4 > # nrcpus avail : 5 > # total memory : 8188340 kB > # cmdline : /usr/bin/perf record -F 1000 lat_mem_rd -P 1 -W 1 -N 1 -t 10 > # event : name = cycles:ppp, , size = 112, { sample_period, sample_freq } = > 1000, sample_type = IP|TID|TIME|PERIOD, disabled = 1, inherit = 1, mmap = > 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, precise_ip = 3, > sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1 > # sibling cores : 1 > # sibling cores : 2 > # sibling cores : 3 > # sibling cores : 4 > # sibling threads : 1 > # sibling threads : 2 > # sibling threads : 3 > # sibling threads : 4 > # CPU 0: Core ID -1, Socket ID -1 > # CPU 1: Core ID 0, Socket ID -1 > # CPU 2: Core ID 0, Socket ID -1 > # CPU 3: Core ID 0, Socket ID -1 > # CPU 4: Core ID 0, Socket ID -1 > # pmu mappings: cpu = 4, software = 1 > # CPU cache info: > # L1 Instruction 32K [1] > # L1 Data 32K [1] > # L1 Instruction 32K [2] > # L1 Data 32K [2] > # L1 Instruction 32K [3] > # L1 Data 32K [3] > # missing features: TRACING_DATA BUILD_ID CPUDESC CPUID NUMA_TOPOLOGY > BRANCH_STACK GROUP_DESC AUXTRACE STAT > # > > > Alex > Many thanks, Alan > On Mon, Mar 26, 2018 at 12:57 AM, Alan Kao wrote: > > > This patch provide a basic PMU, riscv_base_pmu, which supports two > > general hardware event, instructions and cycles. Furthermore, this > > PMU serves as a reference implementation to ease the portings in > > the future. > > > > riscv_base_pmu should be able to run on any RISC-V machine that > > conforms to the Priv-Spec. Note that the latest qemu mode
Re: [PATCH] riscv/ftrace: Export _mcount when FUNCTION_GRAPH_TRACER isn't set
Hi Palmer, Thanks for the refining work! But a small correction here: On Mon, Jun 04, 2018 at 01:30:28PM -0700, Palmer Dabbelt wrote: > From: Alan Kao > > The EXPORT_SYMBOL(_mcount) for RISC-V ended up inside a > CONFIG_FUNCTION_GRAPH_TRACER ifdef. If you enable modules without > enabling CONFIG_FUNCTION_GRAPH_TRACER then you'll get a build error > without this patch because the modules won't be able to find _mcount. the export was inside a CONFIG_DYNAMIC_FTRACE section instead of CONFIG_FUNCTION_GRAPH_TRACER. > The new behavior is to export _mcount whenever CONFIG_FUNCTION_TRACER is > defined. This matches what every other architecture is doing. Also, this patch is just a workaround and there are still issues in bringing up ftrace for modules. For details, please check previous emails between Steve and me. Thanks again for this better commit message. Alan Kao > > Signed-off-by: Alan Kao > Cc: Greentime Hu > Cc: Zong Li > Signed-off-by: Palmer Dabbelt > --- > arch/riscv/kernel/mcount.S | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S > index ce9bdc57a2a1..5721624886a1 100644 > --- a/arch/riscv/kernel/mcount.S > +++ b/arch/riscv/kernel/mcount.S > @@ -126,5 +126,5 @@ do_trace: > RESTORE_ABI_STATE > ret > ENDPROC(_mcount) > -EXPORT_SYMBOL(_mcount) > #endif > +EXPORT_SYMBOL(_mcount) > -- > 2.16.4 >
Re: [PATCH v5 0/2] perf: riscv: Preliminary Perf Event Support on RISC-V
Hi Atish, Palmer, On Tue, Apr 24, 2018 at 06:15:49PM -0700, Atish Patra wrote: > On 4/24/18 5:29 PM, Palmer Dabbelt wrote: > >On Tue, 24 Apr 2018 15:16:16 PDT (-0700), atish.pa...@wdc.com wrote: > >>On 4/24/18 12:44 PM, Palmer Dabbelt wrote: > >>>On Tue, 24 Apr 2018 12:27:26 PDT (-0700), atish.pa...@wdc.com wrote: > >>>>On 4/24/18 11:07 AM, Atish Patra wrote: > >>>>>On 4/19/18 4:28 PM, Alan Kao wrote: > >>>>>However, I got an rcu-stall for the test "47: Event times". > >>>>># ./perf test -v 47 > >>>>Got it working. The test tries to attach the event to CPU0 which doesn't > >>>>exist in HighFive Unleashed. Changing it to cpu1 works. > >>>> > >>>>diff --git a/tools/perf/tests/event-times.c > >>>>b/tools/perf/tests/event-times.c > >>>>index 1a2686f..eb11632f 100644 > >>>>--- a/tools/perf/tests/event-times.c > >>>>+++ b/tools/perf/tests/event-times.c > >>>>@@ -113,9 +113,9 @@ static int attach__cpu_disabled(struct perf_evlist > >>>>*evlist) > >>>> struct cpu_map *cpus; > >>>> int err; > >>>> > >>>>- pr_debug("attaching to CPU 0 as enabled\n"); > >>>>+ pr_debug("attaching to CPU 1 as disabled\n"); > >>>> > >>>>- cpus = cpu_map__new("0"); > >>>>+ cpus = cpu_map__new("1"); > >>>> if (cpus == NULL) { > >>>> pr_debug("failed to call cpu_map__new\n"); > >>>> return -1; > >>>>@@ -142,9 +142,9 @@ static int attach__cpu_enabled(struct perf_evlist > >>>>*evlist) > >>>> struct cpu_map *cpus; > >>>> int err; > >>>> > >>>>- pr_debug("attaching to CPU 0 as enabled\n"); > >>>>+ pr_debug("attaching to CPU 1 as enabled\n"); > >>>> > >>>>- cpus = cpu_map__new("0"); > >>>>+ cpus = cpu_map__new("1"); > >>>> if (cpus == NULL) { > >>>> pr_debug("failed to call cpu_map__new\n"); > >>>> return -1; > >>>> > >>>> > >>>>Palmer, > >>>>Would it be better to officially document it somewhere that CPU0 doesn't > >>>>exist in the HighFive Unleashed board ? > >>>>I fear that there will be other standard tests/code path that may fail > >>>>because of inherent assumption of cpu0 presence. > >>> > >>>I think the best way to fix this is to just have BBL (or whatever the > >>>bootloader is) renumber the CPUs so they're contiguous and begin with 0. > >> > >>Do you mean BBL will update the device tree that kernel eventually parse > >>and set the hart id? > >>Sounds good to me unless it acts as a big hack in future boot loaders. > > > >Right now the machine-mode and supervisor-mode hart IDs are logically > >separate: > >the bootloader just provides the hart ID as a register argument when starting > >the kernel. > > Yes. > > BBL already needs to enumerate the harts by looking through the > >device tree for various other reasons (at least to mask off the harts that > >Linux doesn't support), so it's not that much effort to just maintain a > >mapping > >from supervisor-mode hart IDs to machine-mode hart IDs. > > > > But Linux also parses the device tree to get hart ID in > riscv_of_processor_hart(). This is used to setup the possible/present cpu > map in setup_smp(). > > Thus, Linux also need to see a device tree with cpu0-3 instead of cpu1-4. > Otherwise, present cpu map will be incorrect. Isn't it ? > > >I have some patches floating around that do this, but appear to do it > >incorrectly enough that nothing boots so maybe I'm missing something that > >makes > >this complicated :). > > > > Just a wild guess: May be the because of the above reason ;) > Thanks for the test and discussion. It looks like am implementation issue from Unleash, so ... is there anything I should fix and provide a further patch?
Re: [v2 PATCH] RISC-V: Optimize tlb flush path.
On Tue, Aug 20, 2019 at 08:28:36PM +, Atish Patra wrote: > On Tue, 2019-08-20 at 02:22 -0700, h...@infradead.org wrote: > > On Tue, Aug 20, 2019 at 08:42:19AM +, Atish Patra wrote: > > > cmask NULL is pretty common case and we would be unnecessarily > > > executing bunch of instructions everytime while not saving much. > > > Kernel > > > still have to make an SBI call and OpenSBI is doing a local flush > > > anyways. > > > > > > Looking at the code again, I think we can just use cpumask_weight > > > and > > > do local tlb flush only if local cpu is the only cpu present. > > > > > > Otherwise, it will just fall through and call > > > sbi_remote_sfence_vma(). > > > > Maybe it is just time to split the different cases at a higher level. > > The idea to multiple everything onto a single function always seemed > > odd to me. > > > > FYI, here is what I do for the IPI based tlbflush for the native S- > > mode > > clint prototype, which seems much easier to understand: > > > > http://git.infradead.org/users/hch/riscv.git/commitdiff/ea4067ae61e20fcfcf46a6f6bd1cc25710ce3afe > > This does seem a lot cleaner to me. We can reuse some of the code for > this patch as well. Based on NATIVE_CLINT configuration, it will send > an IPI or SBI call. IMHO, this approach should be avoided because CLINT is compatible to but not mandatory in the privileged spec. In other words, it is possible that a Linux-capable RISC-V platform does not contain a CLINT component but rely on some other mechanism to deal with SW/timer interrupts. > > I can rebase my patch on top of yours and I can send it together or you > can include in your series. > > Let me know your preference. > > -- > Regards, > Atish Best, Alan
Re: [PATCH 08/15] riscv: provide native clint access for M-mode
On Tue, Sep 03, 2019 at 11:48:52AM -0700, Palmer Dabbelt wrote: > On Tue, 27 Aug 2019 23:11:46 PDT (-0700), Christoph Hellwig wrote: > >On Tue, Aug 27, 2019 at 04:37:16PM -0700, Palmer Dabbelt wrote: > >>clint0 would be version 0 of the clint, with is the core-local interrupt > >>controller in rocket chip. It should be "sifive,clint-1.0.0", not > >>"riscv,clint0", as it's a SiFive widget. Unfortunately there are a lot of > >>legacy device trees floating around, but I'm only considering what's been > >>upstream to be actually part of the spec. > >> > >>In this case the code should match on a "sifive,clint-1.0.0", and the > >>device trees should be fixed up to match. We match on "riscv,plic0" for > >>legacy systems, and I guess it makes sense to do something similar here. > > > >IFF we decided to change it I'd rather separate DT noes for the ipi > >bank vs timecmp register vs timeval to support variable layouts. The > >downside is that we can't just boot on unmodified upstream qemu, which > >has used the "riscv,clint0" for years. > > Like I alluded to above, matching on "riscv,clint0" seems reasonable to me > as it's a defacto standard -- we'll just have to make sure that if we ever > end up with a RISC-V CLINT that the DT entry is something else. De facto, but not mandatory. > > As far as splitting the memory maps goes, I don't have a strong opinion but > it seems like that'll introduce more complexity than it's worth. > At least the splitting can keep reminding us and any new comers in the future that CLINT is not (yet) a must in RISC-V landscape. A previous discussion FYI: ( https://lkml.org/lkml/2019/8/20/1361 ) > ___ > linux-riscv mailing list > linux-ri...@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-riscv
Re: [PATCH v2 0/3] Add support for SBI v0.2
On Fri, Sep 27, 2019 at 10:57:45PM +, Atish Patra wrote: > On Fri, 2019-09-27 at 15:19 -0700, Christoph Hellwig wrote: > > On Thu, Sep 26, 2019 at 05:09:12PM -0700, Atish Patra wrote: > > > The Supervisor Binary Interface(SBI) specification[1] now defines a > > > base extension that provides extendability to add future extensions > > > while maintaining backward compatibility with previous versions. > > > The new version is defined as 0.2 and older version is marked as > > > 0.1. > > > > > > This series adds support v0.2 and a unified calling convention > > > implementation between 0.1 and 0.2. It also adds minimal SBI > > > functions > > > from 0.2 as well to keep the series lean. > > > > So before we do this game can be please make sure we have a clean 0.2 > > environment that never uses the legacy extensions as discussed > > before? > > Without that all this work is rather futile. > > > > As per our discussion offline, here are things need to be done to > achieve that. > > 1. Replace timer, sfence and ipi with better alternative APIs > - sbi_set_timer will be same but with new calling convention > - send_ipi and sfence_* apis can be modified in such a way that > - we don't have to use unprivileged load anymore > - Make it scalable > > 2. Drop clear_ipi, console, and shutdown in 0.2. > > We will have a new kernel config (LEGACY_SBI) that can be manually > enabled if older firmware need to be used. By default, LEGACY_SBI will > be disabled and kernel with new SBI will be built. We will have to set > a flag day in a year or so when we can remove the LEGACY_SBI > completely. > > Let us know if it is not an acceptable approach to anybody. > I will post a RFC patch with new alternate v0.2 APIs sometime next > week. > Will this legacy option be compatible will bbl? says, version 1.0.0 or any earlier ones? > > ___ > > linux-riscv mailing list > > linux-ri...@lists.infradead.org > > http://lists.infradead.org/mailman/listinfo/linux-riscv > > -- > Regards, > Atish
Re: [v6 PATCH] RISC-V: Remove unsupported isa string info print
On Tue, Oct 01, 2019 at 03:10:16AM -0700, h...@infradead.org wrote: > On Tue, Oct 01, 2019 at 08:22:37AM +, Atish Patra wrote: > > riscv_of_processor_hartid() or seems to be a better candidate. We > > already check if "rv" is present in isa string or not. I will extend > > that to check for rv64i or rv32i. Is that okay ? > > I'd rather lift the checks out of that into a function that is called > exactly once per hart on boot (and future cpu hotplug). Sorry that I am a bit out of date on this. Is there any related discussion about such checks? Just want to make sure if the check stops here and will not go any further for extensions, Xs and Zs. > > ___ > linux-riscv mailing list > linux-ri...@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-riscv
Re: [PATCH 13/15] riscv: clear the instruction cache and all registers when booting
Please ignore the previous mail, I must have missed this part of the patch, > > > + csrrt0, CSR_MISA > > + andit0, t0, (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D) > > + bnezt0, .Lreset_regs_done > > + In S-mode we were not able to obtain the ISA information in misa, but now the nommu port is in M-mode so this is rather straightforward.
Re: [PATCH 13/15] riscv: clear the instruction cache and all registers when booting
Hi Christoph, On Tue, Aug 13, 2019 at 05:47:45PM +0200, Christoph Hellwig wrote: > When we get booted we want a clear slate without any leaks from previous > supervisors or the firmware. Flush the instruction cache and then clear > all registers to known good values. This is really important for the > upcoming nommu support that runs on M-mode, but can't really harm when > running in S-mode either. Sure. > +#ifdef CONFIG_FPU But it doesn't really mean that the running system has an FPU given CONFIG_FPU enabled. Normally the existence of an FPU is checked in riscv_fill_hwcap by searching device tree, where the code looks like bool has_fpu = false; // this one is global ... #ifdef CONFIG_FPU if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)) has_fpu = true; #endif Or does CONFIG_FPU have a more intuitive meaning when CONFIG_M_MODE is enabled? > + csrrt0, CSR_MISA > + andit0, t0, (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D) > + bnezt0, .Lreset_regs_done > + > + li t1, SR_FS > + csrsCSR_XSTATUS, t1 > + fmv.s.x f0, zero > + fmv.s.x f1, zero > + fmv.s.x f2, zero > + fmv.s.x f3, zero > + fmv.s.x f4, zero > + fmv.s.x f5, zero > + fmv.s.x f6, zero > + fmv.s.x f7, zero > + fmv.s.x f8, zero > + fmv.s.x f9, zero > + fmv.s.x f10, zero > + fmv.s.x f11, zero > + fmv.s.x f12, zero > + fmv.s.x f13, zero > + fmv.s.x f14, zero > + fmv.s.x f15, zero > + fmv.s.x f16, zero > + fmv.s.x f17, zero > + fmv.s.x f18, zero > + fmv.s.x f19, zero > + fmv.s.x f20, zero > + fmv.s.x f21, zero > + fmv.s.x f22, zero > + fmv.s.x f23, zero > + fmv.s.x f24, zero > + fmv.s.x f25, zero > + fmv.s.x f26, zero > + fmv.s.x f27, zero > + fmv.s.x f28, zero > + fmv.s.x f29, zero > + fmv.s.x f30, zero > + fmv.s.x f31, zero > + csrwfcsr, 0 > + /* note that the caller must clear SR_FS */ > +#endif /* CONFIG_FPU */
[PATCH] riscv: fix accessing 8-byte variable from RV32
A memory save operation to 8-byte variable in RV32 is divided into two sw instructions in the put_user macro. The current fixup returns execution flow to the second sw instead of the one after it. This patch fixes this fixup code according to the load access part. Signed-off-by: Alan Kao Cc: Greentime Hu Cc: Vincent Chen --- arch/riscv/include/asm/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index a00168b..fb53a80 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -300,7 +300,7 @@ do { \ " .balign 4\n"\ "4:\n" \ " li %0, %6\n"\ - " jump 2b, %1\n" \ + " jump 3b, %1\n" \ " .previous\n"\ " .section __ex_table,\"a\"\n"\ " .balign " RISCV_SZPTR "\n" \ -- 2.7.4
Re: [PATCH v2] RISC-V: Always compile mm/init.c with cmodel=medany
Hi Anup, Sorry for being late to the party. I think one more thing should move together with setup_vm(): On Mon, Mar 25, 2019 at 03:37:38AM +, Anup Patel wrote: > The Linux RISC-V 32bit kernel is broken after we moved setup_vm() from > kernel/setup.c to mm/init.c because Linux RISC-V 32bit kernel by default > uses cmodel=medlow which results in a non-position-independent setup_vm(). > > This patch fixes Linux RISC-V 32bit kernel booting by: > 1. Forcing cmodel=medany for mm/init.c > 2. Moving remaing MM-related stuff va_pa_offset, pfn_base and >empty_zero_page from kernel/setup.c to mm/init.c > > Fixes: 6f1e9e946f0b ("RISC-V: Move setup_vm() to mm/init.c") > Suggested-by: Christoph Hellwig > Suggested-by: Mike Rapoport > Signed-off-by: Anup Patel > --- > v2: Removed CFLAGS_setup.o from kernel/Makefile and replaced SoBs > --- > arch/riscv/kernel/Makefile | 2 -- > arch/riscv/kernel/setup.c | 8 > arch/riscv/mm/Makefile | 2 ++ > arch/riscv/mm/init.c | 9 + > 4 files changed, 11 insertions(+), 10 deletions(-) > > diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile > index f13f7f276639..8b9780b6bd7f 100644 > --- a/arch/riscv/kernel/Makefile > +++ b/arch/riscv/kernel/Makefile earlier in this file, there are four lines about ftrace, 5 ifdef CONFIG_FTRACE 6 CFLAGS_REMOVE_ftrace.o = -pg 7 CFLAGS_REMOVE_setup.o = -pg 8 endif removing "-pg" flag from setup.o was necessary for ftrace to work, since setup_vm() cannot process the trampoline of ftrace properly. As setup_vm() is being moved to mm/init.c, you may either mark it with a "notrace" attribute with its declaration, or adding corresponding CFLAGS_REMOVE* to mm/Makefile. > @@ -29,8 +29,6 @@ obj-y += vdso.o > obj-y+= cacheinfo.o > obj-y+= vdso/ > > -CFLAGS_setup.o := -mcmodel=medany > - > obj-$(CONFIG_FPU)+= fpu.o > obj-$(CONFIG_SMP)+= smpboot.o > obj-$(CONFIG_SMP)+= smp.o > diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c > index ecb654f6a79e..540a331d1376 100644 > --- a/arch/riscv/kernel/setup.c > +++ b/arch/riscv/kernel/setup.c > @@ -48,14 +48,6 @@ struct screen_info screen_info = { > }; > #endif > > -unsigned long va_pa_offset; > -EXPORT_SYMBOL(va_pa_offset); > -unsigned long pfn_base; > -EXPORT_SYMBOL(pfn_base); > - > -unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] > __page_aligned_bss; > -EXPORT_SYMBOL(empty_zero_page); > - > /* The lucky hart to first increment this variable will boot the other cores > */ > atomic_t hart_lottery; > unsigned long boot_cpu_hartid; > diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile > index eb22ab49b3e0..7307609d405b 100644 > --- a/arch/riscv/mm/Makefile > +++ b/arch/riscv/mm/Makefile > @@ -3,3 +3,5 @@ obj-y += fault.o > obj-y += extable.o > obj-y += ioremap.o > obj-y += cacheflush.o > + > +CFLAGS_init.o := -mcmodel=medany > diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c > index b379a75ac6a6..7a7c454378cb 100644 > --- a/arch/riscv/mm/init.c > +++ b/arch/riscv/mm/init.c > @@ -25,6 +25,10 @@ > #include > #include > > +unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] > + __page_aligned_bss; > +EXPORT_SYMBOL(empty_zero_page); > + > static void __init zone_sizes_init(void) > { > unsigned long max_zone_pfns[MAX_NR_ZONES] = { 0, }; > @@ -143,6 +147,11 @@ void __init setup_bootmem(void) > } > } > > +unsigned long va_pa_offset; > +EXPORT_SYMBOL(va_pa_offset); > +unsigned long pfn_base; > +EXPORT_SYMBOL(pfn_base); > + > pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss; > pgd_t trampoline_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); > > -- > 2.17.1 > > > ___ > linux-riscv mailing list > linux-ri...@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-riscv Alan
Re: [PATCH 1/2] perf: riscv: preliminary RISC-V support
On Sat, Mar 31, 2018 at 03:47:10PM -0700, Alex Solomatnikov wrote: The original guess was that maybe, an counter value on a hart is picked as the minusend, and an old counter value on another hart was recorded as the subtrahend but numerically larger. Then, the overflow causes by that subtraction. Please let me name this guess as "cross-hart subtraction." > You can add a skew between cores in qemu, something like this: > > case CSR_INSTRET: > core_id()*return cpu_get_host_ticks()/10; > break; > case CSR_CYCLE: > return cpu_get_host_ticks(); > break; > However, I tried similar stuff to reproduce the phenomenon but in vain. It seems that the cross-hart subtration doesn't even happen, because generic code handles them. While I am still looking for the proof to it, I would like to have more information on this first: * What is the frequency of that "funny number" event? Was that often? * If you monitor only one hart, will the event disappear? * What will happen if you change the counter_width to fit U54's counter width? * Is the test program you used open-sourced? > Alex > Many thanks, Alan > On Wed, Mar 28, 2018 at 7:30 PM, Alan Kao wrote: > > Hi Alex, > > > > I'm appreciated for your reply and tests. > > > > On Wed, Mar 28, 2018 at 03:58:41PM -0700, Alex Solomatnikov wrote: > >> Did you test this code? > > > > I did test this patch on QEMU's virt model with multi-hart, which is the > > only > > RISC-V machine I have for now. But as I mentioned in > > https://github.com/riscv/riscv-qemu/pull/115 , the hardware counter support > > in QEMU is not fully conformed to the 1.10 Priv-Spec, so I had to slightly > > tweak the code to make reading work. > > > > Specifically, the read to cycle and instret in QEMU looks like this: > > ... > > case CSR_INSTRET: > > case CSR_CYCLE: > > // if (ctr_ok) { > > return cpu_get_host_ticks(); > > // } > > break; > > ... > > and the two lines of comment was the tweak. > > > > On such environment, I did not get anything unexpected. No matter which of > > them > > is requested, QEMU returns the host's tick. > > > >> > >> I got funny numbers when I tried to run it on HiFive Unleashed: > >> > >> perf stat mem-latency > >> ... > >> > >> Performance counter stats for 'mem-latency': > >> > >> 157.907000 task-clock (msec) #0.940 CPUs utilized > >> > >> 1 context-switches #0.006 K/sec > >> > >> 1 cpu-migrations#0.006 K/sec > >> > >> 4102 page-faults #0.026 M/sec > >> > >> 157923752 cycles#1.000 GHz > >> > >> 9223372034948899840 instructions # 58403957087.78 insn > >> per cycle > >> branches > >> > >> branch-misses > >> > >> > >>0.168046000 seconds time elapsed > >> > >> > >> Tracing read_counter(), I see this: > >> > >> Jan 1 00:41:50 buildroot user.info kernel: [ 2510.058809] CPU 3: > >> read_counter idx=0 val=2528358954912 > >> Jan 1 00:41:50 buildroot user.info kernel: [ 2510.063339] CPU 3: > >> read_counter idx=1 val=53892244920 > >> Jan 1 00:41:50 buildroot user.info kernel: [ 2510.118160] CPU 3: > >> read_counter idx=0 val=2528418303035 > >> Jan 1 00:41:50 buildroot user.info kernel: [ 2510.122694] CPU 3: > >> read_counter idx=1 val=53906699665 > >> Jan 1 00:41:50 buildroot user.info kernel: [ 2510.216736] CPU 1: > >> read_counter idx=0 val=2528516878664 > >> Jan 1 00:41:50 buildroot user.info kernel: [ 2510.221270] CPU 1: > >> read_counter idx=1 val=51986369142 > >> > >> It looks like the counter values from different cores are subtracted and > >> wraparound occurs. > >> > > > > Thanks for the hint. It makes sense. 9223372034948899840 is > > 7fff8e66a400, > > which should be a wraparound with the mask I set (63-bit) in the code. > > > > I will try this direction. Ideally, we can solve it by explicitly syncing > > the > > hwc->prev_count when a cpu migration event happens. > > > >> > >> Also, core IDs and socket IDs are wrong in perf report: > >> > > > > As Palmer has replied to this, I have no comment here. > >
Re: [PATCH 1/2] perf: riscv: preliminary RISC-V support
Hi Alex, On Mon, Apr 02, 2018 at 03:36:12PM +0800, Alan Kao wrote: > On Sat, Mar 31, 2018 at 03:47:10PM -0700, Alex Solomatnikov wrote: > > The original guess was that maybe, an counter value on a hart is picked > as the minusend, and an old counter value on another hart was recorded > as the subtrahend but numerically larger. Then, the overflow causes > by that subtraction. Please let me name this guess as > "cross-hart subtraction." > > > You can add a skew between cores in qemu, something like this: > > > > case CSR_INSTRET: > > core_id()*return cpu_get_host_ticks()/10; > > break; > > case CSR_CYCLE: > > return cpu_get_host_ticks(); > > break; > > > > However, I tried similar stuff to reproduce the phenomenon but in vain. > It seems that the > > ***cross-hart subtration doesn't even happen, because generic > code handles them. ... I am sorry that this observation is wrong. With appropriate tweak, we successfully reproduce the behavior and locate the the bug. This will be fix in v2. Thanks for the helps. Alan
[PATCH 0/2] perf: riscv: Preliminary Perf Event Support on RISC-V
This implements the baseline PMU for RISC-V platforms. To ease future PMU portings, a guide is also written, containing perf concepts, arch porting practices and some hints. Changes in v2: - Fix the bug reported by Alex, which was caused by not sufficient initialization. Check https://lkml.org/lkml/2018/3/31/251 for the discussion. Alan Kao (2): perf: riscv: preliminary RISC-V support perf: riscv: Add Document for Future Porting Guide Documentation/riscv/pmu.txt | 249 +++ arch/riscv/Kconfig | 12 + arch/riscv/include/asm/perf_event.h | 76 +- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/perf_event.c | 468 5 files changed, 802 insertions(+), 4 deletions(-) create mode 100644 Documentation/riscv/pmu.txt create mode 100644 arch/riscv/kernel/perf_event.c -- 2.16.2
[PATCH v2 2/2] perf: riscv: Add Document for Future Porting Guide
Cc: Nick Hu Cc: Greentime Hu Signed-off-by: Alan Kao --- Documentation/riscv/pmu.txt | 249 1 file changed, 249 insertions(+) create mode 100644 Documentation/riscv/pmu.txt diff --git a/Documentation/riscv/pmu.txt b/Documentation/riscv/pmu.txt new file mode 100644 index ..a3e930ed5141 --- /dev/null +++ b/Documentation/riscv/pmu.txt @@ -0,0 +1,249 @@ +Supporting PMUs on RISC-V platforms +== +Alan Kao , Mar 2018 + +Introduction + + +As of this writing, perf_event-related features mentioned in The RISC-V ISA +Privileged Version 1.10 are as follows: +(please check the manual for more details) + +* [m|s]counteren +* mcycle[h], cycle[h] +* minstret[h], instret[h] +* mhpeventx, mhpcounterx[h] + +With such function set only, porting perf would require a lot of work, due to +the lack of the following general architectural performance monitoring features: + +* Enabling/Disabling counters + Counters are just free-running all the time in our case. +* Interrupt caused by counter overflow + No such design in the spec. +* Interrupt indicator + It is not possible to have many interrupt ports for all counters, so an + interrupt indicator is required for software to tell which counter has + just overflowed. +* Writing to counters + There will be an SBI to support this since the kernel cannot modify the + counters [1]. Alternatively, some vendor considers to implement + hardware-extension for M-S-U model machines to write counters directly. + +This document aims to provide developers a quick guide on supporting their +PMUs in the kernel. The following sections briefly explain perf' mechanism +and todos. + +You may check previous discussions here [1][2]. Also, it might be helpful +to check the appendix for related kernel structures. + + +1. Initialization +- + +*riscv_pmu* is a global pointer of type *struct riscv_pmu*, which contains +various methods according to perf's internal convention and PMU-specific +parameters. One should declare such instance to represent the PMU. By default, +*riscv_pmu* points to a constant structure *riscv_base_pmu*, which has very +basic support to a baseline QEMU model. + +Then he/she can either assign the instance's pointer to *riscv_pmu* so that +the minimal and already-implemented logic can be leveraged, or invent his/her +own *riscv_init_platform_pmu* implementation. + +In other words, existing sources of *riscv_base_pmu* merely provide a +reference implementation. Developers can flexibly decide how many parts they +can leverage, and in the most extreme case, they can customize every function +according to their needs. + + +2. Event Initialization +--- + +When a user launches a perf command to monitor some events, it is first +interpreted by the userspace perf tool into multiple *perf_event_open* +system calls, and then each of them calls to the body of *event_init* +member function that was assigned in the previous step. In *riscv_base_pmu*'s +case, it is *riscv_event_init*. + +The main purpose of this function is to translate the event provided by user +into bitmap, so that HW-related control registers or counters can directly be +manipulated. The translation is based on the mappings and methods provided in +*riscv_pmu*. + +Note that some features can be done in this stage as well: + +(1) interrupt setting, which is stated in the next section; +(2) privilege level setting (user space only, kernel space only, both); +(3) destructor setting. Normally it is sufficient to apply *riscv_destroy_event*; +(4) tweaks for non-sampling events, which will be utilized by functions such as +*perf_adjust_period*, usually something like the follows: + +if (!is_sampling_event(event)) { +hwc->sample_period = x86_pmu.max_period; +hwc->last_period = hwc->sample_period; +local64_set(&hwc->period_left, hwc->sample_period); +} + +In the case of *riscv_base_pmu*, only (3) is provided for now. + + +3. Interrupt + + +3.1. Interrupt Initialization + +This often occurs at the beginning of the *event_init* method. In common +practice, this should be a code segment like + +int x86_reserve_hardware(void) +{ +int err = 0; + +if (!atomic_inc_not_zero(&pmc_refcount)) { +mutex_lock(&pmc_reserve_mutex); +if (atomic_read(&pmc_refcount) == 0) { +if (!reserve_pmc_hardware()) +err = -EBUSY; +else +reserve_ds_buffers(); +} +if (!err) +atomic_inc(&pmc_refcount); +mutex_unlock(&pmc_reserve_mutex); +} + +return err; +} + +And the magic is in *reserve_pmc_hardware*, which usually does atomic +operations to make im
[PATCH v2 1/2] perf: riscv: preliminary RISC-V support
This patch provide a basic PMU, riscv_base_pmu, which supports two general hardware event, instructions and cycles. Furthermore, this PMU serves as a reference implementation to ease the portings in the future. riscv_base_pmu should be able to run on any RISC-V machine that conforms to the Priv-Spec. Note that the latest qemu model hasn't fully support a proper behavior of Priv-Spec 1.10 yet, but work around should be easy with very small fixes. Please check https://github.com/riscv/riscv-qemu/pull/115 for future updates. Cc: Nick Hu Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 12 + arch/riscv/include/asm/perf_event.h | 76 +- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/perf_event.c | 468 4 files changed, 553 insertions(+), 4 deletions(-) create mode 100644 arch/riscv/kernel/perf_event.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index c22ebe08e902..3fbf19456c9a 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -203,6 +203,18 @@ config RISCV_ISA_C config RISCV_ISA_A def_bool y +menu "PMU type" + depends on PERF_EVENTS + +config RISCV_BASE_PMU + bool "Base Performance Monitoring Unit" + def_bool y + help + A base PMU that serves as a reference implementation and has limited + feature of perf. + +endmenu + endmenu menu "Kernel type" diff --git a/arch/riscv/include/asm/perf_event.h b/arch/riscv/include/asm/perf_event.h index e13d2ff29e83..98e2efb02d25 100644 --- a/arch/riscv/include/asm/perf_event.h +++ b/arch/riscv/include/asm/perf_event.h @@ -1,13 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2018 SiFive + * Copyright (C) 2018 Andes Technology Corporation * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #ifndef _ASM_RISCV_PERF_EVENT_H #define _ASM_RISCV_PERF_EVENT_H +#include +#include + +#define RISCV_BASE_COUNTERS2 + +/* + * The RISCV_MAX_COUNTERS parameter should be specified. + */ + +#ifdef CONFIG_RISCV_BASE_PMU +#define RISCV_MAX_COUNTERS 2 +#endif + +#ifndef RISCV_MAX_COUNTERS +#error "Please provide a valid RISCV_MAX_COUNTERS for the PMU." +#endif + +/* + * These are the indexes of bits in counteren register *minus* 1, + * except for cycle. It would be coherent if it can directly mapped + * to counteren bit definition, but there is a *time* register at + * counteren[1]. Per-cpu structure is scarce resource here. + * + * According to the spec, an implementation can support counter up to + * mhpmcounter31, but many high-end processors has at most 6 general + * PMCs, we give the definition to MHPMCOUNTER8 here. + */ +#define RISCV_PMU_CYCLE0 +#define RISCV_PMU_INSTRET 1 +#define RISCV_PMU_MHPMCOUNTER3 2 +#define RISCV_PMU_MHPMCOUNTER4 3 +#define RISCV_PMU_MHPMCOUNTER5 4 +#define RISCV_PMU_MHPMCOUNTER6 5 +#define RISCV_PMU_MHPMCOUNTER7 6 +#define RISCV_PMU_MHPMCOUNTER8 7 + +#define RISCV_OP_UNSUPP(-EOPNOTSUPP) + +struct cpu_hw_events { + /* # currently enabled events*/ + int n_events; + /* currently enabled events */ + struct perf_event *events[RISCV_MAX_COUNTERS]; + /* vendor-defined PMU data */ + void*platform; +}; + +struct riscv_pmu { + struct pmu *pmu; + + /* generic hw/cache events table */ + const int *hw_events; + const int (*cache_events)[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX]; + /* method used to map hw/cache events */ + int (*map_hw_event)(u64 config); + int (*map_cache_event)(u64 config); + + /* max generic hw events in map */ + int max_events; + /* number total counters, 2(base) + x(general) */ + int num_counters; + /* the width of the counter */ + int counter_width; + + /* vendor-defined PMU features */ + void*platform; +}; + #endif /* _ASM_RISCV_PERF_EVENT_H */ diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index ffa439d4a364..f50d19816757 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -39,5 +39,6 @@ obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER)+= ftrace.o +obj-$(CONFIG_PERF_EVENTS) += perf_event.o clean: diff --git a/arch/riscv/kernel/perf_event.c b/arch/riscv/kernel/perf_event.c new file
Re: [PATCH v2 0/2] perf: riscv: Preliminary Perf Event Support on RISC-V
Sorry for the lack of version prefix in the title. This patchset should be version 2. On Mon, Apr 02, 2018 at 08:31:22PM +0800, Alan Kao wrote: > This implements the baseline PMU for RISC-V platforms. > > To ease future PMU portings, a guide is also written, containing > perf concepts, arch porting practices and some hints. > > Changes in v2: > - Fix the bug reported by Alex, which was caused by not sufficient >initialization. Check https://lkml.org/lkml/2018/3/31/251 for the > discussion. > > Alan Kao (2): > perf: riscv: preliminary RISC-V support > perf: riscv: Add Document for Future Porting Guide > > Documentation/riscv/pmu.txt | 249 +++ > arch/riscv/Kconfig | 12 + > arch/riscv/include/asm/perf_event.h | 76 +- > arch/riscv/kernel/Makefile | 1 + > arch/riscv/kernel/perf_event.c | 468 > > 5 files changed, 802 insertions(+), 4 deletions(-) > create mode 100644 Documentation/riscv/pmu.txt > create mode 100644 arch/riscv/kernel/perf_event.c > > -- > 2.16.2 >
Re: [PATCH v4 1/2] perf: riscv: preliminary RISC-V support
On Thu, Apr 19, 2018 at 12:46:24PM -0700, Atish Patra wrote: > On 4/17/18 7:13 PM, Alan Kao wrote: > >This patch provide a basic PMU, riscv_base_pmu, which supports two > >general hardware event, instructions and cycles. Furthermore, this > >PMU serves as a reference implementation to ease the portings in > >the future. > > > >riscv_base_pmu should be able to run on any RISC-V machine that > >conforms to the Priv-Spec. Note that the latest qemu model hasn't > >fully support a proper behavior of Priv-Spec 1.10 yet, but work > >around should be easy with very small fixes. Please check > >https://github.com/riscv/riscv-qemu/pull/115 for future updates. > > > >Cc: Nick Hu > >Cc: Greentime Hu > >Signed-off-by: Alan Kao > >--- > > arch/riscv/Kconfig | 13 + > > arch/riscv/include/asm/perf_event.h | 79 - > > arch/riscv/kernel/Makefile | 1 + > > arch/riscv/kernel/perf_event.c | 482 > > 4 files changed, 571 insertions(+), 4 deletions(-) > > create mode 100644 arch/riscv/kernel/perf_event.c > > > >diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig > >index c22ebe08e902..90d9c8e50377 100644 > >--- a/arch/riscv/Kconfig > >+++ b/arch/riscv/Kconfig > Some check patch errors. > > ERROR: spaces required around that '>=' (ctx:WxV) > #517: FILE: arch/riscv/kernel/perf_event.c:356: > + if (riscv_pmu->irq >=0 && riscv_pmu->handle_irq) { > ^ > > ERROR: spaces required around that '>=' (ctx:WxV) > #529: FILE: arch/riscv/kernel/perf_event.c:368: > + if (riscv_pmu->irq >=0) { > ^ > > WARNING: braces {} are not necessary for single statement blocks > #529: FILE: arch/riscv/kernel/perf_event.c:368: > + if (riscv_pmu->irq >=0) { > + free_irq(riscv_pmu->irq, NULL); > + } > > WARNING: DT compatible string "riscv,base-pmu" appears un-documented -- > check ./Documentation/devicetree/bindings/ > #626: FILE: arch/riscv/kernel/perf_event.c:465: > + {.compatible = "riscv,base-pmu",.data = &riscv_base_pmu}, > > ERROR: trailing whitespace > #634: FILE: arch/riscv/kernel/perf_event.c:473: > +^I$ > > ERROR: do not use assignment in if condition > #635: FILE: arch/riscv/kernel/perf_event.c:474: > + if (node && (of_id = of_match_node(riscv_pmu_of_ids, node))) > > total: 4 errors, 3 warnings, 595 lines checked > > > Regards, > Atish Thanks for pointing this out. I happened to develop this patchset on a machine without the post-commit settings. A new version is ready.
[PATCH v5 2/2] perf: riscv: Add Document for Future Porting Guide
Reviewed-by: Alex Solomatnikov Cc: Nick Hu Cc: Greentime Hu Signed-off-by: Alan Kao --- Documentation/riscv/pmu.txt | 249 1 file changed, 249 insertions(+) create mode 100644 Documentation/riscv/pmu.txt diff --git a/Documentation/riscv/pmu.txt b/Documentation/riscv/pmu.txt new file mode 100644 index ..b29f03a6d82f --- /dev/null +++ b/Documentation/riscv/pmu.txt @@ -0,0 +1,249 @@ +Supporting PMUs on RISC-V platforms +== +Alan Kao , Mar 2018 + +Introduction + + +As of this writing, perf_event-related features mentioned in The RISC-V ISA +Privileged Version 1.10 are as follows: +(please check the manual for more details) + +* [m|s]counteren +* mcycle[h], cycle[h] +* minstret[h], instret[h] +* mhpeventx, mhpcounterx[h] + +With such function set only, porting perf would require a lot of work, due to +the lack of the following general architectural performance monitoring features: + +* Enabling/Disabling counters + Counters are just free-running all the time in our case. +* Interrupt caused by counter overflow + No such feature in the spec. +* Interrupt indicator + It is not possible to have many interrupt ports for all counters, so an + interrupt indicator is required for software to tell which counter has + just overflowed. +* Writing to counters + There will be an SBI to support this since the kernel cannot modify the + counters [1]. Alternatively, some vendor considers to implement + hardware-extension for M-S-U model machines to write counters directly. + +This document aims to provide developers a quick guide on supporting their +PMUs in the kernel. The following sections briefly explain perf' mechanism +and todos. + +You may check previous discussions here [1][2]. Also, it might be helpful +to check the appendix for related kernel structures. + + +1. Initialization +- + +*riscv_pmu* is a global pointer of type *struct riscv_pmu*, which contains +various methods according to perf's internal convention and PMU-specific +parameters. One should declare such instance to represent the PMU. By default, +*riscv_pmu* points to a constant structure *riscv_base_pmu*, which has very +basic support to a baseline QEMU model. + +Then he/she can either assign the instance's pointer to *riscv_pmu* so that +the minimal and already-implemented logic can be leveraged, or invent his/her +own *riscv_init_platform_pmu* implementation. + +In other words, existing sources of *riscv_base_pmu* merely provide a +reference implementation. Developers can flexibly decide how many parts they +can leverage, and in the most extreme case, they can customize every function +according to their needs. + + +2. Event Initialization +--- + +When a user launches a perf command to monitor some events, it is first +interpreted by the userspace perf tool into multiple *perf_event_open* +system calls, and then each of them calls to the body of *event_init* +member function that was assigned in the previous step. In *riscv_base_pmu*'s +case, it is *riscv_event_init*. + +The main purpose of this function is to translate the event provided by user +into bitmap, so that HW-related control registers or counters can directly be +manipulated. The translation is based on the mappings and methods provided in +*riscv_pmu*. + +Note that some features can be done in this stage as well: + +(1) interrupt setting, which is stated in the next section; +(2) privilege level setting (user space only, kernel space only, both); +(3) destructor setting. Normally it is sufficient to apply *riscv_destroy_event*; +(4) tweaks for non-sampling events, which will be utilized by functions such as +*perf_adjust_period*, usually something like the follows: + +if (!is_sampling_event(event)) { +hwc->sample_period = x86_pmu.max_period; +hwc->last_period = hwc->sample_period; +local64_set(&hwc->period_left, hwc->sample_period); +} + +In the case of *riscv_base_pmu*, only (3) is provided for now. + + +3. Interrupt + + +3.1. Interrupt Initialization + +This often occurs at the beginning of the *event_init* method. In common +practice, this should be a code segment like + +int x86_reserve_hardware(void) +{ +int err = 0; + +if (!atomic_inc_not_zero(&pmc_refcount)) { +mutex_lock(&pmc_reserve_mutex); +if (atomic_read(&pmc_refcount) == 0) { +if (!reserve_pmc_hardware()) +err = -EBUSY; +else +reserve_ds_buffers(); +} +if (!err) +atomic_inc(&pmc_refcount); +mutex_unlock(&pmc_reserve_mutex); +} + +return err; +} + +And the magic is in *reserve_pmc_hardware*, which usually does atomic +ope
[PATCH v5 0/2] perf: riscv: Preliminary Perf Event Support on RISC-V
This implements the baseline PMU for RISC-V platforms. To ease future PMU portings, a guide is also written, containing perf concepts, arch porting practices and some hints. Changes in v5: - Fix patch errors from checkpatch.pl. Changes in v4: - Fix several compilation errors. Sorry for that. - Raise a warning in the write_counter body. Changes in v3: - Fix typos in the document. - Change the initialization routine from statically assigning PMU to device-tree-based methods, and set default to the PMU proposed in this patch. Changes in v2: - Fix the bug reported by Alex, which was caused by not sufficient initialization. Check https://lkml.org/lkml/2018/3/31/251 for the discussion. Alan Kao (2): perf: riscv: preliminary RISC-V support perf: riscv: Add Document for Future Porting Guide Documentation/riscv/pmu.txt | 249 ++ arch/riscv/Kconfig | 13 + arch/riscv/include/asm/perf_event.h | 79 - arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/perf_event.c | 485 5 files changed, 823 insertions(+), 4 deletions(-) create mode 100644 Documentation/riscv/pmu.txt create mode 100644 arch/riscv/kernel/perf_event.c -- 2.17.0
[PATCH v5 1/2] perf: riscv: preliminary RISC-V support
This patch provide a basic PMU, riscv_base_pmu, which supports two general hardware event, instructions and cycles. Furthermore, this PMU serves as a reference implementation to ease the portings in the future. riscv_base_pmu should be able to run on any RISC-V machine that conforms to the Priv-Spec. Note that the latest qemu model hasn't fully support a proper behavior of Priv-Spec 1.10 yet, but work around should be easy with very small fixes. Please check https://github.com/riscv/riscv-qemu/pull/115 for future updates. Cc: Nick Hu Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 13 + arch/riscv/include/asm/perf_event.h | 79 - arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/perf_event.c | 485 4 files changed, 574 insertions(+), 4 deletions(-) create mode 100644 arch/riscv/kernel/perf_event.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index c22ebe08e902..90d9c8e50377 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -203,6 +203,19 @@ config RISCV_ISA_C config RISCV_ISA_A def_bool y +menu "supported PMU type" + depends on PERF_EVENTS + +config RISCV_BASE_PMU + bool "Base Performance Monitoring Unit" + def_bool y + help + A base PMU that serves as a reference implementation and has limited + feature of perf. It can run on any RISC-V machines so serves as the + fallback, but this option can also be disable to reduce kernel size. + +endmenu + endmenu menu "Kernel type" diff --git a/arch/riscv/include/asm/perf_event.h b/arch/riscv/include/asm/perf_event.h index e13d2ff29e83..0e638a0c3feb 100644 --- a/arch/riscv/include/asm/perf_event.h +++ b/arch/riscv/include/asm/perf_event.h @@ -1,13 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2018 SiFive + * Copyright (C) 2018 Andes Technology Corporation * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #ifndef _ASM_RISCV_PERF_EVENT_H #define _ASM_RISCV_PERF_EVENT_H +#include +#include + +#define RISCV_BASE_COUNTERS2 + +/* + * The RISCV_MAX_COUNTERS parameter should be specified. + */ + +#ifdef CONFIG_RISCV_BASE_PMU +#define RISCV_MAX_COUNTERS 2 +#endif + +#ifndef RISCV_MAX_COUNTERS +#error "Please provide a valid RISCV_MAX_COUNTERS for the PMU." +#endif + +/* + * These are the indexes of bits in counteren register *minus* 1, + * except for cycle. It would be coherent if it can directly mapped + * to counteren bit definition, but there is a *time* register at + * counteren[1]. Per-cpu structure is scarce resource here. + * + * According to the spec, an implementation can support counter up to + * mhpmcounter31, but many high-end processors has at most 6 general + * PMCs, we give the definition to MHPMCOUNTER8 here. + */ +#define RISCV_PMU_CYCLE0 +#define RISCV_PMU_INSTRET 1 +#define RISCV_PMU_MHPMCOUNTER3 2 +#define RISCV_PMU_MHPMCOUNTER4 3 +#define RISCV_PMU_MHPMCOUNTER5 4 +#define RISCV_PMU_MHPMCOUNTER6 5 +#define RISCV_PMU_MHPMCOUNTER7 6 +#define RISCV_PMU_MHPMCOUNTER8 7 + +#define RISCV_OP_UNSUPP(-EOPNOTSUPP) + +struct cpu_hw_events { + /* # currently enabled events*/ + int n_events; + /* currently enabled events */ + struct perf_event *events[RISCV_MAX_COUNTERS]; + /* vendor-defined PMU data */ + void*platform; +}; + +struct riscv_pmu { + struct pmu *pmu; + + /* generic hw/cache events table */ + const int *hw_events; + const int (*cache_events)[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX]; + /* method used to map hw/cache events */ + int (*map_hw_event)(u64 config); + int (*map_cache_event)(u64 config); + + /* max generic hw events in map */ + int max_events; + /* number total counters, 2(base) + x(general) */ + int num_counters; + /* the width of the counter */ + int counter_width; + + /* vendor-defined PMU features */ + void*platform; + + irqreturn_t (*handle_irq)(int irq_num, void *dev); + int irq; +}; + #endif /* _ASM_RISCV_PERF_EVENT_H */ diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index ffa439d4a364..f50d19816757 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -39,5 +39,6 @@ obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o obj-$(
[PATCH v3 0/2] perf: riscv: Preliminary Perf Event Support on RISC-V
This implements the baseline PMU for RISC-V platforms. To ease future PMU portings, a guide is also written, containing perf concepts, arch porting practices and some hints. Changes in v3: - Fix typos in the document. - Change the initialization routine from statically assigning PMU to device-tree-based methods, and set default to the PMU proposed in this patch. Changes in v2: - Fix the bug reported by Alex, which was caused by not sufficient initialization. Check https://lkml.org/lkml/2018/3/31/251 for the discussion. Alan Kao (2): perf: riscv: preliminary RISC-V support perf: riscv: Add Document for Future Porting Guide Documentation/riscv/pmu.txt | 249 +++ arch/riscv/Kconfig | 13 + arch/riscv/include/asm/perf_event.h | 78 - arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/perf_event.c | 478 5 files changed, 815 insertions(+), 4 deletions(-) create mode 100644 Documentation/riscv/pmu.txt create mode 100644 arch/riscv/kernel/perf_event.c -- 2.17.0
[PATCH v3 2/2] perf: riscv: Add Document for Future Porting Guide
Reviewed-by: Alex Solomatnikov Cc: Nick Hu Cc: Greentime Hu Signed-off-by: Alan Kao --- Documentation/riscv/pmu.txt | 249 1 file changed, 249 insertions(+) create mode 100644 Documentation/riscv/pmu.txt diff --git a/Documentation/riscv/pmu.txt b/Documentation/riscv/pmu.txt new file mode 100644 index ..b29f03a6d82f --- /dev/null +++ b/Documentation/riscv/pmu.txt @@ -0,0 +1,249 @@ +Supporting PMUs on RISC-V platforms +== +Alan Kao , Mar 2018 + +Introduction + + +As of this writing, perf_event-related features mentioned in The RISC-V ISA +Privileged Version 1.10 are as follows: +(please check the manual for more details) + +* [m|s]counteren +* mcycle[h], cycle[h] +* minstret[h], instret[h] +* mhpeventx, mhpcounterx[h] + +With such function set only, porting perf would require a lot of work, due to +the lack of the following general architectural performance monitoring features: + +* Enabling/Disabling counters + Counters are just free-running all the time in our case. +* Interrupt caused by counter overflow + No such feature in the spec. +* Interrupt indicator + It is not possible to have many interrupt ports for all counters, so an + interrupt indicator is required for software to tell which counter has + just overflowed. +* Writing to counters + There will be an SBI to support this since the kernel cannot modify the + counters [1]. Alternatively, some vendor considers to implement + hardware-extension for M-S-U model machines to write counters directly. + +This document aims to provide developers a quick guide on supporting their +PMUs in the kernel. The following sections briefly explain perf' mechanism +and todos. + +You may check previous discussions here [1][2]. Also, it might be helpful +to check the appendix for related kernel structures. + + +1. Initialization +- + +*riscv_pmu* is a global pointer of type *struct riscv_pmu*, which contains +various methods according to perf's internal convention and PMU-specific +parameters. One should declare such instance to represent the PMU. By default, +*riscv_pmu* points to a constant structure *riscv_base_pmu*, which has very +basic support to a baseline QEMU model. + +Then he/she can either assign the instance's pointer to *riscv_pmu* so that +the minimal and already-implemented logic can be leveraged, or invent his/her +own *riscv_init_platform_pmu* implementation. + +In other words, existing sources of *riscv_base_pmu* merely provide a +reference implementation. Developers can flexibly decide how many parts they +can leverage, and in the most extreme case, they can customize every function +according to their needs. + + +2. Event Initialization +--- + +When a user launches a perf command to monitor some events, it is first +interpreted by the userspace perf tool into multiple *perf_event_open* +system calls, and then each of them calls to the body of *event_init* +member function that was assigned in the previous step. In *riscv_base_pmu*'s +case, it is *riscv_event_init*. + +The main purpose of this function is to translate the event provided by user +into bitmap, so that HW-related control registers or counters can directly be +manipulated. The translation is based on the mappings and methods provided in +*riscv_pmu*. + +Note that some features can be done in this stage as well: + +(1) interrupt setting, which is stated in the next section; +(2) privilege level setting (user space only, kernel space only, both); +(3) destructor setting. Normally it is sufficient to apply *riscv_destroy_event*; +(4) tweaks for non-sampling events, which will be utilized by functions such as +*perf_adjust_period*, usually something like the follows: + +if (!is_sampling_event(event)) { +hwc->sample_period = x86_pmu.max_period; +hwc->last_period = hwc->sample_period; +local64_set(&hwc->period_left, hwc->sample_period); +} + +In the case of *riscv_base_pmu*, only (3) is provided for now. + + +3. Interrupt + + +3.1. Interrupt Initialization + +This often occurs at the beginning of the *event_init* method. In common +practice, this should be a code segment like + +int x86_reserve_hardware(void) +{ +int err = 0; + +if (!atomic_inc_not_zero(&pmc_refcount)) { +mutex_lock(&pmc_reserve_mutex); +if (atomic_read(&pmc_refcount) == 0) { +if (!reserve_pmc_hardware()) +err = -EBUSY; +else +reserve_ds_buffers(); +} +if (!err) +atomic_inc(&pmc_refcount); +mutex_unlock(&pmc_reserve_mutex); +} + +return err; +} + +And the magic is in *reserve_pmc_hardware*, which usually does atomic +ope
[PATCH v3 1/2] perf: riscv: preliminary RISC-V support
This patch provide a basic PMU, riscv_base_pmu, which supports two general hardware event, instructions and cycles. Furthermore, this PMU serves as a reference implementation to ease the portings in the future. riscv_base_pmu should be able to run on any RISC-V machine that conforms to the Priv-Spec. Note that the latest qemu model hasn't fully support a proper behavior of Priv-Spec 1.10 yet, but work around should be easy with very small fixes. Please check https://github.com/riscv/riscv-qemu/pull/115 for future updates. Cc: Nick Hu Cc: Greentime Hu Signed-off-by: Alan Kao --- arch/riscv/Kconfig | 13 + arch/riscv/include/asm/perf_event.h | 78 - arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/perf_event.c | 478 4 files changed, 566 insertions(+), 4 deletions(-) create mode 100644 arch/riscv/kernel/perf_event.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index c22ebe08e902..90d9c8e50377 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -203,6 +203,19 @@ config RISCV_ISA_C config RISCV_ISA_A def_bool y +menu "supported PMU type" + depends on PERF_EVENTS + +config RISCV_BASE_PMU + bool "Base Performance Monitoring Unit" + def_bool y + help + A base PMU that serves as a reference implementation and has limited + feature of perf. It can run on any RISC-V machines so serves as the + fallback, but this option can also be disable to reduce kernel size. + +endmenu + endmenu menu "Kernel type" diff --git a/arch/riscv/include/asm/perf_event.h b/arch/riscv/include/asm/perf_event.h index e13d2ff29e83..eb6bb1c46387 100644 --- a/arch/riscv/include/asm/perf_event.h +++ b/arch/riscv/include/asm/perf_event.h @@ -1,13 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2018 SiFive + * Copyright (C) 2018 Andes Technology Corporation * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #ifndef _ASM_RISCV_PERF_EVENT_H #define _ASM_RISCV_PERF_EVENT_H +#include +#include + +#define RISCV_BASE_COUNTERS2 + +/* + * The RISCV_MAX_COUNTERS parameter should be specified. + */ + +#ifdef CONFIG_RISCV_BASE_PMU +#define RISCV_MAX_COUNTERS 2 +#endif + +#ifndef RISCV_MAX_COUNTERS +#error "Please provide a valid RISCV_MAX_COUNTERS for the PMU." +#endif + +/* + * These are the indexes of bits in counteren register *minus* 1, + * except for cycle. It would be coherent if it can directly mapped + * to counteren bit definition, but there is a *time* register at + * counteren[1]. Per-cpu structure is scarce resource here. + * + * According to the spec, an implementation can support counter up to + * mhpmcounter31, but many high-end processors has at most 6 general + * PMCs, we give the definition to MHPMCOUNTER8 here. + */ +#define RISCV_PMU_CYCLE0 +#define RISCV_PMU_INSTRET 1 +#define RISCV_PMU_MHPMCOUNTER3 2 +#define RISCV_PMU_MHPMCOUNTER4 3 +#define RISCV_PMU_MHPMCOUNTER5 4 +#define RISCV_PMU_MHPMCOUNTER6 5 +#define RISCV_PMU_MHPMCOUNTER7 6 +#define RISCV_PMU_MHPMCOUNTER8 7 + +#define RISCV_OP_UNSUPP(-EOPNOTSUPP) + +struct cpu_hw_events { + /* # currently enabled events*/ + int n_events; + /* currently enabled events */ + struct perf_event *events[RISCV_MAX_COUNTERS]; + /* vendor-defined PMU data */ + void*platform; +}; + +struct riscv_pmu { + struct pmu *pmu; + + /* generic hw/cache events table */ + const int *hw_events; + const int (*cache_events)[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX]; + /* method used to map hw/cache events */ + int (*map_hw_event)(u64 config); + int (*map_cache_event)(u64 config); + + /* max generic hw events in map */ + int max_events; + /* number total counters, 2(base) + x(general) */ + int num_counters; + /* the width of the counter */ + int counter_width; + + /* vendor-defined PMU features */ + void*platform; + + irqreturn_t (*handle_irq)(int irq_num, void *dev); +}; + #endif /* _ASM_RISCV_PERF_EVENT_H */ diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index ffa439d4a364..f50d19816757 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -39,5 +39,6 @@ obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o obj-$(CONFIG_DYNAMIC_FTRACE) += mco
Re: [PATCH] riscv/ftrace: Fix the problem modules cannot find _mcount
On Tue, May 08, 2018 at 09:11:42AM -0400, Steven Rostedt wrote: > On Tue, 8 May 2018 11:21:57 +0800 > Alan Kao wrote: > > > Enabling ftrace and module support at the same time fails the kernel > > build process, because modules cannot find the _mcount symbol. This > > patch fixes this issue. > > I think you have a much bigger issue. > Yes, we do, but not this one. Let me state more detail later. > > > > Signed-off-by: Alan Kao > > Cc: Greentime Hu > > Cc: Zong Li > > --- > > arch/riscv/kernel/mcount.S | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S > > index ce9bdc57a2a1..5721624886a1 100644 > > --- a/arch/riscv/kernel/mcount.S > > +++ b/arch/riscv/kernel/mcount.S > > @@ -126,5 +126,5 @@ do_trace: > > RESTORE_ABI_STATE > > ret > > ENDPROC(_mcount) > > -EXPORT_SYMBOL(_mcount) > > #endif > > +EXPORT_SYMBOL(_mcount) > > How does this work? How do you export _mcount if _mcount isn't even > defined? _mcount is defined. This EXPORT_SYMBOL and the _mcount body was inside a "#ifndef CONFIG_DYNAMIC_FTRACE" section, so if the config has dynamic ftrace disabled, _mcount is visible. For the dynamic ftrace case, there is a code snippet in this file: > ENTRY(ftrace_stub) > #ifdef CONFIG_DYNAMIC_FTRACE > .global _mcount > .set_mcount, ftrace_stub > #endif >ret > ENDPROC(ftrace_stub) so the _mcount symbol is visible in the kernel, but not for modules. As a result, a module build always fails, because _mcount is neither exported, nor aliased to a defined symbol. That's the simple purpose of this patch: we just want to eliminate the errors during the kernel build process. > > -- Steve Talking about some bigger issues here, there will be twofold. 1. This patch lacks call-site collecting mechanism. This feature requires a pattern check in recordmcount.pl. With this, section __mcount_loc is properly constructed, and the call-sites will be registered during the loading stage. However, the loading will then fail at the first try of make_nop, due to the instruction check. This is thus the second issue. 2. The instruction check for kernel texts is not applicable to module texts. The check expects a call instruction to _mcount, but here it is a call to the .plt section of the module. After referencing the implementation of arm64, I think it would need much more work to have make_nop's and make_call's behavior right. Quick summary: This patch ensures that a kernel build will not fail because of the _mcount-missing problem. But ftrace cannot trace loading modules for now due to the stated reasons. Thanks, Alan Kao