Commit 4e4101cf authored by Palmer Dabbelt's avatar Palmer Dabbelt

riscv: Add support to no-FPU systems

This patchset adds an option, CONFIG_FPU, to enable/disable floating-
point support within the kernel.  The 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.
Signed-off-by: default avatarPalmer Dabbelt <palmer@sifive.com>
parents aef53f97 9411ec60
...@@ -210,6 +210,15 @@ config RISCV_BASE_PMU ...@@ -210,6 +210,15 @@ config RISCV_BASE_PMU
endmenu 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 endmenu
menu "Kernel features" menu "Kernel features"
......
...@@ -26,7 +26,6 @@ ifeq ($(CONFIG_ARCH_RV64I),y) ...@@ -26,7 +26,6 @@ ifeq ($(CONFIG_ARCH_RV64I),y)
KBUILD_CFLAGS += -mabi=lp64 KBUILD_CFLAGS += -mabi=lp64
KBUILD_AFLAGS += -mabi=lp64 KBUILD_AFLAGS += -mabi=lp64
KBUILD_MARCH = rv64im
KBUILD_LDFLAGS += -melf64lriscv KBUILD_LDFLAGS += -melf64lriscv
else else
BITS := 32 BITS := 32
...@@ -34,22 +33,20 @@ else ...@@ -34,22 +33,20 @@ else
KBUILD_CFLAGS += -mabi=ilp32 KBUILD_CFLAGS += -mabi=ilp32
KBUILD_AFLAGS += -mabi=ilp32 KBUILD_AFLAGS += -mabi=ilp32
KBUILD_MARCH = rv32im
KBUILD_LDFLAGS += -melf32lriscv KBUILD_LDFLAGS += -melf32lriscv
endif endif
KBUILD_CFLAGS += -Wall KBUILD_CFLAGS += -Wall
ifeq ($(CONFIG_RISCV_ISA_A),y) # ISA string setting
KBUILD_ARCH_A = a riscv-march-$(CONFIG_ARCH_RV32I) := rv32im
endif riscv-march-$(CONFIG_ARCH_RV64I) := rv64im
ifeq ($(CONFIG_RISCV_ISA_C),y) riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a
KBUILD_ARCH_C = c riscv-march-$(CONFIG_FPU) := $(riscv-march-y)fd
endif riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c
KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y))
KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)fd$(KBUILD_ARCH_C) KBUILD_AFLAGS += -march=$(riscv-march-y)
KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_ARCH_A)$(KBUILD_ARCH_C)
KBUILD_CFLAGS += -mno-save-restore KBUILD_CFLAGS += -mno-save-restore
KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET) KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET)
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/csr.h> #include <asm/csr.h>
#ifdef CONFIG_FPU
extern void __fstate_save(struct task_struct *save_to); extern void __fstate_save(struct task_struct *save_to);
extern void __fstate_restore(struct task_struct *restore_from); extern void __fstate_restore(struct task_struct *restore_from);
...@@ -55,6 +56,14 @@ static inline void __switch_to_aux(struct task_struct *prev, ...@@ -55,6 +56,14 @@ static inline void __switch_to_aux(struct task_struct *prev,
fstate_restore(next, task_pt_regs(next)); fstate_restore(next, task_pt_regs(next));
} }
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)
#endif
extern struct task_struct *__switch_to(struct task_struct *, extern struct task_struct *__switch_to(struct task_struct *,
struct task_struct *); struct task_struct *);
...@@ -62,7 +71,8 @@ extern struct task_struct *__switch_to(struct task_struct *, ...@@ -62,7 +71,8 @@ extern struct task_struct *__switch_to(struct task_struct *,
do { \ do { \
struct task_struct *__prev = (prev); \ struct task_struct *__prev = (prev); \
struct task_struct *__next = (next); \ struct task_struct *__next = (next); \
__switch_to_aux(__prev, __next); \ if (has_fpu) \
__switch_to_aux(__prev, __next); \
((last) = __switch_to(__prev, __next)); \ ((last) = __switch_to(__prev, __next)); \
} while (0) } while (0)
......
...@@ -31,6 +31,7 @@ obj-y += vdso/ ...@@ -31,6 +31,7 @@ obj-y += vdso/
CFLAGS_setup.o := -mcmodel=medany CFLAGS_setup.o := -mcmodel=medany
obj-$(CONFIG_FPU) += fpu.o
obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smpboot.o
obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULES) += module.o
......
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
#include <asm/hwcap.h> #include <asm/hwcap.h>
unsigned long elf_hwcap __read_mostly; unsigned long elf_hwcap __read_mostly;
#ifdef CONFIG_FPU
bool has_fpu __read_mostly;
#endif
void riscv_fill_hwcap(void) void riscv_fill_hwcap(void)
{ {
...@@ -65,4 +68,9 @@ void riscv_fill_hwcap(void) ...@@ -65,4 +68,9 @@ void riscv_fill_hwcap(void)
} }
pr_info("elf_hwcap is 0x%lx", elf_hwcap); 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
} }
...@@ -357,93 +357,6 @@ ENTRY(__switch_to) ...@@ -357,93 +357,6 @@ ENTRY(__switch_to)
ret ret
ENDPROC(__switch_to) 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" .section ".rodata"
/* Exception vector table */ /* Exception vector table */
ENTRY(excp_vect_table) ENTRY(excp_vect_table)
......
/* 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 <linux/linkage.h>
#include <asm/asm.h>
#include <asm/csr.h>
#include <asm/asm-offsets.h>
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)
...@@ -76,7 +76,9 @@ void show_regs(struct pt_regs *regs) ...@@ -76,7 +76,9 @@ void show_regs(struct pt_regs *regs)
void start_thread(struct pt_regs *regs, unsigned long pc, void start_thread(struct pt_regs *regs, unsigned long pc,
unsigned long sp) unsigned long sp)
{ {
regs->sstatus = SR_SPIE /* User mode, irqs on */ | SR_FS_INITIAL; regs->sstatus = SR_SPIE;
if (has_fpu)
regs->sstatus |= SR_FS_INITIAL;
regs->sepc = pc; regs->sepc = pc;
regs->sp = sp; regs->sp = sp;
set_fs(USER_DS); set_fs(USER_DS);
...@@ -84,12 +86,14 @@ void start_thread(struct pt_regs *regs, unsigned long pc, ...@@ -84,12 +86,14 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
void flush_thread(void) void flush_thread(void)
{ {
#ifdef CONFIG_FPU
/* /*
* Reset FPU context * Reset FPU context
* frm: round to nearest, ties to even (IEEE default) * frm: round to nearest, ties to even (IEEE default)
* fflags: accrued exceptions cleared * fflags: accrued exceptions cleared
*/ */
memset(&current->thread.fstate, 0, sizeof(current->thread.fstate)); memset(&current->thread.fstate, 0, sizeof(current->thread.fstate));
#endif
} }
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
......
...@@ -37,45 +37,69 @@ struct rt_sigframe { ...@@ -37,45 +37,69 @@ struct rt_sigframe {
struct ucontext uc; struct ucontext uc;
}; };
static long restore_d_state(struct pt_regs *regs, #ifdef CONFIG_FPU
struct __riscv_d_ext_state __user *state) static long restore_fp_state(struct pt_regs *regs,
union __riscv_fp_state *sc_fpregs)
{ {
long err; long err;
struct __riscv_d_ext_state __user *state = &sc_fpregs->d;
size_t i;
err = __copy_from_user(&current->thread.fstate, state, sizeof(*state)); err = __copy_from_user(&current->thread.fstate, state, sizeof(*state));
if (likely(!err)) if (unlikely(err))
fstate_restore(current, regs); 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; return err;
} }
static long save_d_state(struct pt_regs *regs, static long save_fp_state(struct pt_regs *regs,
struct __riscv_d_ext_state __user *state) 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); fstate_save(current, regs);
return __copy_to_user(state, &current->thread.fstate, sizeof(*state)); err = __copy_to_user(state, &current->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;
} }
#else
#define save_fp_state(task, regs) (0)
#define restore_fp_state(task, regs) (0)
#endif
static long restore_sigcontext(struct pt_regs *regs, static long restore_sigcontext(struct pt_regs *regs,
struct sigcontext __user *sc) struct sigcontext __user *sc)
{ {
long err; long err;
size_t i;
/* sc_regs is structured the same as the start of pt_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)); err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
if (unlikely(err))
return err;
/* Restore the floating-point state. */ /* Restore the floating-point state. */
err = restore_d_state(regs, &sc->sc_fpregs.d); if (has_fpu)
if (unlikely(err)) err |= restore_fp_state(regs, &sc->sc_fpregs);
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;
}
return err; return err;
} }
...@@ -124,14 +148,11 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, ...@@ -124,14 +148,11 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
{ {
struct sigcontext __user *sc = &frame->uc.uc_mcontext; struct sigcontext __user *sc = &frame->uc.uc_mcontext;
long err; long err;
size_t i;
/* sc_regs is structured the same as the start of pt_regs */ /* sc_regs is structured the same as the start of pt_regs */
err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
/* Save the floating-point state. */ /* Save the floating-point state. */
err |= save_d_state(regs, &sc->sc_fpregs.d); if (has_fpu)
/* We support no other extension state at this time. */ err |= save_fp_state(regs, &sc->sc_fpregs);
for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++)
err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment