linux/arch/mips/loongson/loongson-3/cop2-ex.c
Maciej W. Rozycki 9b26616c8d MIPS: Respect the ISA level in FCSR handling
Define the central place the default FCSR value is set from, initialised
in `cpu_probe'.  Determine the FCSR mask applied to values written to
the register with CTC1 in the full emulation mode and via ptrace(2),
according to the ISA level of processor hardware or the writability of
bits 31:18 if actual FPU hardware is used.

Software may rely on FCSR bits whose functions our emulator does not
implement, so it should not allow them to be set or software may get
confused.  For ptrace(2) it's just sanity.

[ralf@linux-mips.org: Fixed double inclusion of <asm/current.h>.]

Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/9711/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2015-04-08 01:10:37 +02:00

64 lines
1.6 KiB
C

/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2014 Lemote Corporation.
* written by Huacai Chen <chenhc@lemote.com>
*
* based on arch/mips/cavium-octeon/cpu.c
* Copyright (C) 2009 Wind River Systems,
* written by Ralf Baechle <ralf@linux-mips.org>
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/notifier.h>
#include <asm/fpu.h>
#include <asm/cop2.h>
#include <asm/current.h>
#include <asm/mipsregs.h>
static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
void *data)
{
int fpu_owned;
int fr = !test_thread_flag(TIF_32BIT_FPREGS);
switch (action) {
case CU2_EXCEPTION:
preempt_disable();
fpu_owned = __is_fpu_owner();
if (!fr)
set_c0_status(ST0_CU1 | ST0_CU2);
else
set_c0_status(ST0_CU1 | ST0_CU2 | ST0_FR);
enable_fpu_hazard();
KSTK_STATUS(current) |= (ST0_CU1 | ST0_CU2);
if (fr)
KSTK_STATUS(current) |= ST0_FR;
else
KSTK_STATUS(current) &= ~ST0_FR;
/* If FPU is owned, we needn't init or restore fp */
if (!fpu_owned) {
set_thread_flag(TIF_USEDFPU);
if (!used_math()) {
_init_fpu(current->thread.fpu.fcr31);
set_used_math();
} else
_restore_fp(current);
}
preempt_enable();
return NOTIFY_STOP; /* Don't call default notifier */
}
return NOTIFY_OK; /* Let default notifier send signals */
}
static int __init loongson_cu2_setup(void)
{
return cu2_notifier(loongson_cu2_call, 0);
}
early_initcall(loongson_cu2_setup);