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: Palmer Dabbelt <palmer@sifive.com>
This commit is contained in:
@@ -31,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
|
||||
|
@@ -22,6 +22,9 @@
|
||||
#include <asm/hwcap.h>
|
||||
|
||||
unsigned long elf_hwcap __read_mostly;
|
||||
#ifdef CONFIG_FPU
|
||||
bool has_fpu __read_mostly;
|
||||
#endif
|
||||
|
||||
void riscv_fill_hwcap(void)
|
||||
{
|
||||
@@ -65,4 +68,9 @@ void riscv_fill_hwcap(void)
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
|
106
arch/riscv/kernel/fpu.S
Normal file
106
arch/riscv/kernel/fpu.S
Normal file
@@ -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 <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)
|
||||
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 = SR_SPIE;
|
||||
if (has_fpu)
|
||||
regs->sstatus |= SR_FS_INITIAL;
|
||||
regs->sepc = pc;
|
||||
regs->sp = sp;
|
||||
set_fs(USER_DS);
|
||||
@@ -84,12 +86,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)
|
||||
|
@@ -37,45 +37,69 @@ struct rt_sigframe {
|
||||
struct ucontext uc;
|
||||
};
|
||||
|
||||
static 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));
|
||||
if (likely(!err))
|
||||
fstate_restore(current, regs);
|
||||
return err;
|
||||
}
|
||||
|
||||
static long save_d_state(struct pt_regs *regs,
|
||||
struct __riscv_d_ext_state __user *state)
|
||||
{
|
||||
fstate_save(current, regs);
|
||||
return __copy_to_user(state, ¤t->thread.fstate, sizeof(*state));
|
||||
}
|
||||
|
||||
static long restore_sigcontext(struct pt_regs *regs,
|
||||
struct sigcontext __user *sc)
|
||||
#ifdef CONFIG_FPU
|
||||
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;
|
||||
/* 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);
|
||||
|
||||
err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state));
|
||||
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->sc_fpregs.q.reserved); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) {
|
||||
u32 value;
|
||||
err = __get_user(value, &sc->sc_fpregs.q.reserved[i]);
|
||||
|
||||
err = __get_user(value, &sc_fpregs->q.reserved[i]);
|
||||
if (unlikely(err))
|
||||
break;
|
||||
if (value != 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
long err;
|
||||
/* 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. */
|
||||
if (has_fpu)
|
||||
err |= restore_fp_state(regs, &sc->sc_fpregs);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -124,14 +148,11 @@ 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]);
|
||||
if (has_fpu)
|
||||
err |= save_fp_state(regs, &sc->sc_fpregs);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
Fai riferimento in un nuovo problema
Block a user