mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-05-21 14:46:57 +00:00
MIPS: Support for 64-bit FP with O32 binaries
CPUs implementing MIPS32 R2 may include a 64-bit FPU, just as MIPS64 CPUs do. In order to preserve backwards compatibility a 64-bit FPU will act like a 32-bit FPU (by accessing doubles from the least significant 32 bits of an even-odd pair of FP registers) when the Status.FR bit is zero, again just like a mips64 CPU. The standard O32 ABI is defined expecting a 32-bit FPU, however recent toolchains support use of a 64-bit FPU from an O32 MIPS32 executable. When an ELF executable is built to use a 64-bit FPU a new flag (EF_MIPS_FP64) is set in the ELF header. With this patch the kernel will check the EF_MIPS_FP64 flag when executing an O32 binary, and set Status.FR accordingly. The addition of O32 64-bit FP support lessens the opportunity for optimisation in the FPU emulator, so a CONFIG_MIPS_O32_FP64_SUPPORT Kconfig option is introduced to allow this support to be disabled for those that don't require it. Inspired by an earlier patch by Leonid Yegoshin, but implemented more cleanly & correctly. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Cc: Paul Burton <paul.burton@imgtec.com> Patchwork: https://patchwork.linux-mips.org/patch/6154/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
56a22d21bf
commit
597ce1723e
19 changed files with 449 additions and 236 deletions
|
@ -2335,6 +2335,23 @@ config CC_STACKPROTECTOR
|
||||||
|
|
||||||
This feature requires gcc version 4.2 or above.
|
This feature requires gcc version 4.2 or above.
|
||||||
|
|
||||||
|
config MIPS_O32_FP64_SUPPORT
|
||||||
|
bool "Support for O32 binaries using 64-bit FP"
|
||||||
|
depends on 32BIT || MIPS32_O32
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
When this is enabled, the kernel will support use of 64-bit floating
|
||||||
|
point registers with binaries using the O32 ABI along with the
|
||||||
|
EF_MIPS_FP64 ELF header flag (typically built with -mfp64). On
|
||||||
|
32-bit MIPS systems this support is at the cost of increasing the
|
||||||
|
size and complexity of the compiled FPU emulator. Thus if you are
|
||||||
|
running a MIPS32 system and know that none of your userland binaries
|
||||||
|
will require 64-bit floating point, you may wish to reduce the size
|
||||||
|
of your kernel & potentially improve FP emulation performance by
|
||||||
|
saying N here.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
config USE_OF
|
config USE_OF
|
||||||
bool
|
bool
|
||||||
select OF
|
select OF
|
||||||
|
|
|
@ -12,27 +12,6 @@
|
||||||
#include <asm/fpregdef.h>
|
#include <asm/fpregdef.h>
|
||||||
#include <asm/mipsregs.h>
|
#include <asm/mipsregs.h>
|
||||||
|
|
||||||
.macro fpu_save_double thread status tmp1=t0
|
|
||||||
cfc1 \tmp1, fcr31
|
|
||||||
sdc1 $f0, THREAD_FPR0(\thread)
|
|
||||||
sdc1 $f2, THREAD_FPR2(\thread)
|
|
||||||
sdc1 $f4, THREAD_FPR4(\thread)
|
|
||||||
sdc1 $f6, THREAD_FPR6(\thread)
|
|
||||||
sdc1 $f8, THREAD_FPR8(\thread)
|
|
||||||
sdc1 $f10, THREAD_FPR10(\thread)
|
|
||||||
sdc1 $f12, THREAD_FPR12(\thread)
|
|
||||||
sdc1 $f14, THREAD_FPR14(\thread)
|
|
||||||
sdc1 $f16, THREAD_FPR16(\thread)
|
|
||||||
sdc1 $f18, THREAD_FPR18(\thread)
|
|
||||||
sdc1 $f20, THREAD_FPR20(\thread)
|
|
||||||
sdc1 $f22, THREAD_FPR22(\thread)
|
|
||||||
sdc1 $f24, THREAD_FPR24(\thread)
|
|
||||||
sdc1 $f26, THREAD_FPR26(\thread)
|
|
||||||
sdc1 $f28, THREAD_FPR28(\thread)
|
|
||||||
sdc1 $f30, THREAD_FPR30(\thread)
|
|
||||||
sw \tmp1, THREAD_FCR31(\thread)
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro fpu_save_single thread tmp=t0
|
.macro fpu_save_single thread tmp=t0
|
||||||
cfc1 \tmp, fcr31
|
cfc1 \tmp, fcr31
|
||||||
swc1 $f0, THREAD_FPR0(\thread)
|
swc1 $f0, THREAD_FPR0(\thread)
|
||||||
|
@ -70,27 +49,6 @@
|
||||||
sw \tmp, THREAD_FCR31(\thread)
|
sw \tmp, THREAD_FCR31(\thread)
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro fpu_restore_double thread status tmp=t0
|
|
||||||
lw \tmp, THREAD_FCR31(\thread)
|
|
||||||
ldc1 $f0, THREAD_FPR0(\thread)
|
|
||||||
ldc1 $f2, THREAD_FPR2(\thread)
|
|
||||||
ldc1 $f4, THREAD_FPR4(\thread)
|
|
||||||
ldc1 $f6, THREAD_FPR6(\thread)
|
|
||||||
ldc1 $f8, THREAD_FPR8(\thread)
|
|
||||||
ldc1 $f10, THREAD_FPR10(\thread)
|
|
||||||
ldc1 $f12, THREAD_FPR12(\thread)
|
|
||||||
ldc1 $f14, THREAD_FPR14(\thread)
|
|
||||||
ldc1 $f16, THREAD_FPR16(\thread)
|
|
||||||
ldc1 $f18, THREAD_FPR18(\thread)
|
|
||||||
ldc1 $f20, THREAD_FPR20(\thread)
|
|
||||||
ldc1 $f22, THREAD_FPR22(\thread)
|
|
||||||
ldc1 $f24, THREAD_FPR24(\thread)
|
|
||||||
ldc1 $f26, THREAD_FPR26(\thread)
|
|
||||||
ldc1 $f28, THREAD_FPR28(\thread)
|
|
||||||
ldc1 $f30, THREAD_FPR30(\thread)
|
|
||||||
ctc1 \tmp, fcr31
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro fpu_restore_single thread tmp=t0
|
.macro fpu_restore_single thread tmp=t0
|
||||||
lw \tmp, THREAD_FCR31(\thread)
|
lw \tmp, THREAD_FCR31(\thread)
|
||||||
lwc1 $f0, THREAD_FPR0(\thread)
|
lwc1 $f0, THREAD_FPR0(\thread)
|
||||||
|
|
|
@ -13,102 +13,6 @@
|
||||||
#include <asm/fpregdef.h>
|
#include <asm/fpregdef.h>
|
||||||
#include <asm/mipsregs.h>
|
#include <asm/mipsregs.h>
|
||||||
|
|
||||||
.macro fpu_save_16even thread tmp=t0
|
|
||||||
cfc1 \tmp, fcr31
|
|
||||||
sdc1 $f0, THREAD_FPR0(\thread)
|
|
||||||
sdc1 $f2, THREAD_FPR2(\thread)
|
|
||||||
sdc1 $f4, THREAD_FPR4(\thread)
|
|
||||||
sdc1 $f6, THREAD_FPR6(\thread)
|
|
||||||
sdc1 $f8, THREAD_FPR8(\thread)
|
|
||||||
sdc1 $f10, THREAD_FPR10(\thread)
|
|
||||||
sdc1 $f12, THREAD_FPR12(\thread)
|
|
||||||
sdc1 $f14, THREAD_FPR14(\thread)
|
|
||||||
sdc1 $f16, THREAD_FPR16(\thread)
|
|
||||||
sdc1 $f18, THREAD_FPR18(\thread)
|
|
||||||
sdc1 $f20, THREAD_FPR20(\thread)
|
|
||||||
sdc1 $f22, THREAD_FPR22(\thread)
|
|
||||||
sdc1 $f24, THREAD_FPR24(\thread)
|
|
||||||
sdc1 $f26, THREAD_FPR26(\thread)
|
|
||||||
sdc1 $f28, THREAD_FPR28(\thread)
|
|
||||||
sdc1 $f30, THREAD_FPR30(\thread)
|
|
||||||
sw \tmp, THREAD_FCR31(\thread)
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro fpu_save_16odd thread
|
|
||||||
sdc1 $f1, THREAD_FPR1(\thread)
|
|
||||||
sdc1 $f3, THREAD_FPR3(\thread)
|
|
||||||
sdc1 $f5, THREAD_FPR5(\thread)
|
|
||||||
sdc1 $f7, THREAD_FPR7(\thread)
|
|
||||||
sdc1 $f9, THREAD_FPR9(\thread)
|
|
||||||
sdc1 $f11, THREAD_FPR11(\thread)
|
|
||||||
sdc1 $f13, THREAD_FPR13(\thread)
|
|
||||||
sdc1 $f15, THREAD_FPR15(\thread)
|
|
||||||
sdc1 $f17, THREAD_FPR17(\thread)
|
|
||||||
sdc1 $f19, THREAD_FPR19(\thread)
|
|
||||||
sdc1 $f21, THREAD_FPR21(\thread)
|
|
||||||
sdc1 $f23, THREAD_FPR23(\thread)
|
|
||||||
sdc1 $f25, THREAD_FPR25(\thread)
|
|
||||||
sdc1 $f27, THREAD_FPR27(\thread)
|
|
||||||
sdc1 $f29, THREAD_FPR29(\thread)
|
|
||||||
sdc1 $f31, THREAD_FPR31(\thread)
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro fpu_save_double thread status tmp
|
|
||||||
sll \tmp, \status, 5
|
|
||||||
bgez \tmp, 2f
|
|
||||||
fpu_save_16odd \thread
|
|
||||||
2:
|
|
||||||
fpu_save_16even \thread \tmp
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro fpu_restore_16even thread tmp=t0
|
|
||||||
lw \tmp, THREAD_FCR31(\thread)
|
|
||||||
ldc1 $f0, THREAD_FPR0(\thread)
|
|
||||||
ldc1 $f2, THREAD_FPR2(\thread)
|
|
||||||
ldc1 $f4, THREAD_FPR4(\thread)
|
|
||||||
ldc1 $f6, THREAD_FPR6(\thread)
|
|
||||||
ldc1 $f8, THREAD_FPR8(\thread)
|
|
||||||
ldc1 $f10, THREAD_FPR10(\thread)
|
|
||||||
ldc1 $f12, THREAD_FPR12(\thread)
|
|
||||||
ldc1 $f14, THREAD_FPR14(\thread)
|
|
||||||
ldc1 $f16, THREAD_FPR16(\thread)
|
|
||||||
ldc1 $f18, THREAD_FPR18(\thread)
|
|
||||||
ldc1 $f20, THREAD_FPR20(\thread)
|
|
||||||
ldc1 $f22, THREAD_FPR22(\thread)
|
|
||||||
ldc1 $f24, THREAD_FPR24(\thread)
|
|
||||||
ldc1 $f26, THREAD_FPR26(\thread)
|
|
||||||
ldc1 $f28, THREAD_FPR28(\thread)
|
|
||||||
ldc1 $f30, THREAD_FPR30(\thread)
|
|
||||||
ctc1 \tmp, fcr31
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro fpu_restore_16odd thread
|
|
||||||
ldc1 $f1, THREAD_FPR1(\thread)
|
|
||||||
ldc1 $f3, THREAD_FPR3(\thread)
|
|
||||||
ldc1 $f5, THREAD_FPR5(\thread)
|
|
||||||
ldc1 $f7, THREAD_FPR7(\thread)
|
|
||||||
ldc1 $f9, THREAD_FPR9(\thread)
|
|
||||||
ldc1 $f11, THREAD_FPR11(\thread)
|
|
||||||
ldc1 $f13, THREAD_FPR13(\thread)
|
|
||||||
ldc1 $f15, THREAD_FPR15(\thread)
|
|
||||||
ldc1 $f17, THREAD_FPR17(\thread)
|
|
||||||
ldc1 $f19, THREAD_FPR19(\thread)
|
|
||||||
ldc1 $f21, THREAD_FPR21(\thread)
|
|
||||||
ldc1 $f23, THREAD_FPR23(\thread)
|
|
||||||
ldc1 $f25, THREAD_FPR25(\thread)
|
|
||||||
ldc1 $f27, THREAD_FPR27(\thread)
|
|
||||||
ldc1 $f29, THREAD_FPR29(\thread)
|
|
||||||
ldc1 $f31, THREAD_FPR31(\thread)
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro fpu_restore_double thread status tmp
|
|
||||||
sll \tmp, \status, 5
|
|
||||||
bgez \tmp, 1f # 16 register mode?
|
|
||||||
|
|
||||||
fpu_restore_16odd \thread
|
|
||||||
1: fpu_restore_16even \thread \tmp
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro cpu_save_nonscratch thread
|
.macro cpu_save_nonscratch thread
|
||||||
LONG_S s0, THREAD_REG16(\thread)
|
LONG_S s0, THREAD_REG16(\thread)
|
||||||
LONG_S s1, THREAD_REG17(\thread)
|
LONG_S s1, THREAD_REG17(\thread)
|
||||||
|
|
|
@ -62,6 +62,113 @@
|
||||||
.endm
|
.endm
|
||||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||||
|
|
||||||
|
.macro fpu_save_16even thread tmp=t0
|
||||||
|
cfc1 \tmp, fcr31
|
||||||
|
sdc1 $f0, THREAD_FPR0(\thread)
|
||||||
|
sdc1 $f2, THREAD_FPR2(\thread)
|
||||||
|
sdc1 $f4, THREAD_FPR4(\thread)
|
||||||
|
sdc1 $f6, THREAD_FPR6(\thread)
|
||||||
|
sdc1 $f8, THREAD_FPR8(\thread)
|
||||||
|
sdc1 $f10, THREAD_FPR10(\thread)
|
||||||
|
sdc1 $f12, THREAD_FPR12(\thread)
|
||||||
|
sdc1 $f14, THREAD_FPR14(\thread)
|
||||||
|
sdc1 $f16, THREAD_FPR16(\thread)
|
||||||
|
sdc1 $f18, THREAD_FPR18(\thread)
|
||||||
|
sdc1 $f20, THREAD_FPR20(\thread)
|
||||||
|
sdc1 $f22, THREAD_FPR22(\thread)
|
||||||
|
sdc1 $f24, THREAD_FPR24(\thread)
|
||||||
|
sdc1 $f26, THREAD_FPR26(\thread)
|
||||||
|
sdc1 $f28, THREAD_FPR28(\thread)
|
||||||
|
sdc1 $f30, THREAD_FPR30(\thread)
|
||||||
|
sw \tmp, THREAD_FCR31(\thread)
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro fpu_save_16odd thread
|
||||||
|
.set push
|
||||||
|
.set mips64r2
|
||||||
|
sdc1 $f1, THREAD_FPR1(\thread)
|
||||||
|
sdc1 $f3, THREAD_FPR3(\thread)
|
||||||
|
sdc1 $f5, THREAD_FPR5(\thread)
|
||||||
|
sdc1 $f7, THREAD_FPR7(\thread)
|
||||||
|
sdc1 $f9, THREAD_FPR9(\thread)
|
||||||
|
sdc1 $f11, THREAD_FPR11(\thread)
|
||||||
|
sdc1 $f13, THREAD_FPR13(\thread)
|
||||||
|
sdc1 $f15, THREAD_FPR15(\thread)
|
||||||
|
sdc1 $f17, THREAD_FPR17(\thread)
|
||||||
|
sdc1 $f19, THREAD_FPR19(\thread)
|
||||||
|
sdc1 $f21, THREAD_FPR21(\thread)
|
||||||
|
sdc1 $f23, THREAD_FPR23(\thread)
|
||||||
|
sdc1 $f25, THREAD_FPR25(\thread)
|
||||||
|
sdc1 $f27, THREAD_FPR27(\thread)
|
||||||
|
sdc1 $f29, THREAD_FPR29(\thread)
|
||||||
|
sdc1 $f31, THREAD_FPR31(\thread)
|
||||||
|
.set pop
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro fpu_save_double thread status tmp
|
||||||
|
#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
|
||||||
|
sll \tmp, \status, 5
|
||||||
|
bgez \tmp, 10f
|
||||||
|
fpu_save_16odd \thread
|
||||||
|
10:
|
||||||
|
#endif
|
||||||
|
fpu_save_16even \thread \tmp
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro fpu_restore_16even thread tmp=t0
|
||||||
|
lw \tmp, THREAD_FCR31(\thread)
|
||||||
|
ldc1 $f0, THREAD_FPR0(\thread)
|
||||||
|
ldc1 $f2, THREAD_FPR2(\thread)
|
||||||
|
ldc1 $f4, THREAD_FPR4(\thread)
|
||||||
|
ldc1 $f6, THREAD_FPR6(\thread)
|
||||||
|
ldc1 $f8, THREAD_FPR8(\thread)
|
||||||
|
ldc1 $f10, THREAD_FPR10(\thread)
|
||||||
|
ldc1 $f12, THREAD_FPR12(\thread)
|
||||||
|
ldc1 $f14, THREAD_FPR14(\thread)
|
||||||
|
ldc1 $f16, THREAD_FPR16(\thread)
|
||||||
|
ldc1 $f18, THREAD_FPR18(\thread)
|
||||||
|
ldc1 $f20, THREAD_FPR20(\thread)
|
||||||
|
ldc1 $f22, THREAD_FPR22(\thread)
|
||||||
|
ldc1 $f24, THREAD_FPR24(\thread)
|
||||||
|
ldc1 $f26, THREAD_FPR26(\thread)
|
||||||
|
ldc1 $f28, THREAD_FPR28(\thread)
|
||||||
|
ldc1 $f30, THREAD_FPR30(\thread)
|
||||||
|
ctc1 \tmp, fcr31
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro fpu_restore_16odd thread
|
||||||
|
.set push
|
||||||
|
.set mips64r2
|
||||||
|
ldc1 $f1, THREAD_FPR1(\thread)
|
||||||
|
ldc1 $f3, THREAD_FPR3(\thread)
|
||||||
|
ldc1 $f5, THREAD_FPR5(\thread)
|
||||||
|
ldc1 $f7, THREAD_FPR7(\thread)
|
||||||
|
ldc1 $f9, THREAD_FPR9(\thread)
|
||||||
|
ldc1 $f11, THREAD_FPR11(\thread)
|
||||||
|
ldc1 $f13, THREAD_FPR13(\thread)
|
||||||
|
ldc1 $f15, THREAD_FPR15(\thread)
|
||||||
|
ldc1 $f17, THREAD_FPR17(\thread)
|
||||||
|
ldc1 $f19, THREAD_FPR19(\thread)
|
||||||
|
ldc1 $f21, THREAD_FPR21(\thread)
|
||||||
|
ldc1 $f23, THREAD_FPR23(\thread)
|
||||||
|
ldc1 $f25, THREAD_FPR25(\thread)
|
||||||
|
ldc1 $f27, THREAD_FPR27(\thread)
|
||||||
|
ldc1 $f29, THREAD_FPR29(\thread)
|
||||||
|
ldc1 $f31, THREAD_FPR31(\thread)
|
||||||
|
.set pop
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro fpu_restore_double thread status tmp
|
||||||
|
#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
|
||||||
|
sll \tmp, \status, 5
|
||||||
|
bgez \tmp, 10f # 16 register mode?
|
||||||
|
|
||||||
|
fpu_restore_16odd \thread
|
||||||
|
10:
|
||||||
|
#endif
|
||||||
|
fpu_restore_16even \thread \tmp
|
||||||
|
.endm
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Temporary until all gas have MT ASE support
|
* Temporary until all gas have MT ASE support
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#define EF_MIPS_ABI2 0x00000020
|
#define EF_MIPS_ABI2 0x00000020
|
||||||
#define EF_MIPS_OPTIONS_FIRST 0x00000080
|
#define EF_MIPS_OPTIONS_FIRST 0x00000080
|
||||||
#define EF_MIPS_32BITMODE 0x00000100
|
#define EF_MIPS_32BITMODE 0x00000100
|
||||||
|
#define EF_MIPS_FP64 0x00000200
|
||||||
#define EF_MIPS_ABI 0x0000f000
|
#define EF_MIPS_ABI 0x0000f000
|
||||||
#define EF_MIPS_ARCH 0xf0000000
|
#define EF_MIPS_ARCH 0xf0000000
|
||||||
|
|
||||||
|
@ -175,6 +176,18 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
|
||||||
|
|
||||||
#ifdef CONFIG_32BIT
|
#ifdef CONFIG_32BIT
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In order to be sure that we don't attempt to execute an O32 binary which
|
||||||
|
* requires 64 bit FP (FR=1) on a system which does not support it we refuse
|
||||||
|
* to execute any binary which has bits specified by the following macro set
|
||||||
|
* in its ELF header flags.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_MIPS_O32_FP64_SUPPORT
|
||||||
|
# define __MIPS_O32_FP64_MUST_BE_ZERO 0
|
||||||
|
#else
|
||||||
|
# define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is used to ensure we don't load something for the wrong architecture.
|
* This is used to ensure we don't load something for the wrong architecture.
|
||||||
*/
|
*/
|
||||||
|
@ -191,6 +204,8 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
|
||||||
__res = 0; \
|
__res = 0; \
|
||||||
if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
|
if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
|
||||||
((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
|
((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
|
||||||
|
__res = 0; \
|
||||||
|
if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \
|
||||||
__res = 0; \
|
__res = 0; \
|
||||||
\
|
\
|
||||||
__res; \
|
__res; \
|
||||||
|
@ -249,6 +264,11 @@ extern struct mips_abi mips_abi_n32;
|
||||||
|
|
||||||
#define SET_PERSONALITY(ex) \
|
#define SET_PERSONALITY(ex) \
|
||||||
do { \
|
do { \
|
||||||
|
if ((ex).e_flags & EF_MIPS_FP64) \
|
||||||
|
clear_thread_flag(TIF_32BIT_FPREGS); \
|
||||||
|
else \
|
||||||
|
set_thread_flag(TIF_32BIT_FPREGS); \
|
||||||
|
\
|
||||||
if (personality(current->personality) != PER_LINUX) \
|
if (personality(current->personality) != PER_LINUX) \
|
||||||
set_personality(PER_LINUX); \
|
set_personality(PER_LINUX); \
|
||||||
\
|
\
|
||||||
|
@ -271,14 +291,18 @@ do { \
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_MIPS32_O32
|
#ifdef CONFIG_MIPS32_O32
|
||||||
#define __SET_PERSONALITY32_O32() \
|
#define __SET_PERSONALITY32_O32(ex) \
|
||||||
do { \
|
do { \
|
||||||
set_thread_flag(TIF_32BIT_REGS); \
|
set_thread_flag(TIF_32BIT_REGS); \
|
||||||
set_thread_flag(TIF_32BIT_ADDR); \
|
set_thread_flag(TIF_32BIT_ADDR); \
|
||||||
|
\
|
||||||
|
if (!((ex).e_flags & EF_MIPS_FP64)) \
|
||||||
|
set_thread_flag(TIF_32BIT_FPREGS); \
|
||||||
|
\
|
||||||
current->thread.abi = &mips_abi_32; \
|
current->thread.abi = &mips_abi_32; \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define __SET_PERSONALITY32_O32() \
|
#define __SET_PERSONALITY32_O32(ex) \
|
||||||
do { } while (0)
|
do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -289,7 +313,7 @@ do { \
|
||||||
((ex).e_flags & EF_MIPS_ABI) == 0) \
|
((ex).e_flags & EF_MIPS_ABI) == 0) \
|
||||||
__SET_PERSONALITY32_N32(); \
|
__SET_PERSONALITY32_N32(); \
|
||||||
else \
|
else \
|
||||||
__SET_PERSONALITY32_O32(); \
|
__SET_PERSONALITY32_O32(ex); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define __SET_PERSONALITY32(ex) do { } while (0)
|
#define __SET_PERSONALITY32(ex) do { } while (0)
|
||||||
|
@ -300,6 +324,7 @@ do { \
|
||||||
unsigned int p; \
|
unsigned int p; \
|
||||||
\
|
\
|
||||||
clear_thread_flag(TIF_32BIT_REGS); \
|
clear_thread_flag(TIF_32BIT_REGS); \
|
||||||
|
clear_thread_flag(TIF_32BIT_FPREGS); \
|
||||||
clear_thread_flag(TIF_32BIT_ADDR); \
|
clear_thread_flag(TIF_32BIT_ADDR); \
|
||||||
\
|
\
|
||||||
if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \
|
if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \
|
||||||
|
|
|
@ -33,11 +33,48 @@ extern void _init_fpu(void);
|
||||||
extern void _save_fp(struct task_struct *);
|
extern void _save_fp(struct task_struct *);
|
||||||
extern void _restore_fp(struct task_struct *);
|
extern void _restore_fp(struct task_struct *);
|
||||||
|
|
||||||
#define __enable_fpu() \
|
/*
|
||||||
do { \
|
* This enum specifies a mode in which we want the FPU to operate, for cores
|
||||||
set_c0_status(ST0_CU1); \
|
* which implement the Status.FR bit. Note that FPU_32BIT & FPU_64BIT
|
||||||
enable_fpu_hazard(); \
|
* purposefully have the values 0 & 1 respectively, so that an integer value
|
||||||
} while (0)
|
* of Status.FR can be trivially casted to the corresponding enum fpu_mode.
|
||||||
|
*/
|
||||||
|
enum fpu_mode {
|
||||||
|
FPU_32BIT = 0, /* FR = 0 */
|
||||||
|
FPU_64BIT, /* FR = 1 */
|
||||||
|
FPU_AS_IS,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int __enable_fpu(enum fpu_mode mode)
|
||||||
|
{
|
||||||
|
int fr;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case FPU_AS_IS:
|
||||||
|
/* just enable the FPU in its current mode */
|
||||||
|
set_c0_status(ST0_CU1);
|
||||||
|
enable_fpu_hazard();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case FPU_64BIT:
|
||||||
|
#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_MIPS64))
|
||||||
|
/* we only have a 32-bit FPU */
|
||||||
|
return SIGFPE;
|
||||||
|
#endif
|
||||||
|
/* fall through */
|
||||||
|
case FPU_32BIT:
|
||||||
|
/* set CU1 & change FR appropriately */
|
||||||
|
fr = (int)mode;
|
||||||
|
change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0));
|
||||||
|
enable_fpu_hazard();
|
||||||
|
|
||||||
|
/* check FR has the desired value */
|
||||||
|
return (!!(read_c0_status() & ST0_FR) == !!fr) ? 0 : SIGFPE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define __disable_fpu() \
|
#define __disable_fpu() \
|
||||||
do { \
|
do { \
|
||||||
|
@ -57,27 +94,46 @@ static inline int is_fpu_owner(void)
|
||||||
return cpu_has_fpu && __is_fpu_owner();
|
return cpu_has_fpu && __is_fpu_owner();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __own_fpu(void)
|
static inline int __own_fpu(void)
|
||||||
{
|
{
|
||||||
__enable_fpu();
|
enum fpu_mode mode;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mode = !test_thread_flag(TIF_32BIT_FPREGS);
|
||||||
|
ret = __enable_fpu(mode);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
KSTK_STATUS(current) |= ST0_CU1;
|
KSTK_STATUS(current) |= ST0_CU1;
|
||||||
|
if (mode == FPU_64BIT)
|
||||||
|
KSTK_STATUS(current) |= ST0_FR;
|
||||||
|
else /* mode == FPU_32BIT */
|
||||||
|
KSTK_STATUS(current) &= ~ST0_FR;
|
||||||
|
|
||||||
set_thread_flag(TIF_USEDFPU);
|
set_thread_flag(TIF_USEDFPU);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void own_fpu_inatomic(int restore)
|
static inline int own_fpu_inatomic(int restore)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (cpu_has_fpu && !__is_fpu_owner()) {
|
if (cpu_has_fpu && !__is_fpu_owner()) {
|
||||||
__own_fpu();
|
ret = __own_fpu();
|
||||||
if (restore)
|
if (restore && !ret)
|
||||||
_restore_fp(current);
|
_restore_fp(current);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void own_fpu(int restore)
|
static inline int own_fpu(int restore)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
own_fpu_inatomic(restore);
|
ret = own_fpu_inatomic(restore);
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void lose_fpu(int save)
|
static inline void lose_fpu(int save)
|
||||||
|
@ -93,16 +149,21 @@ static inline void lose_fpu(int save)
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void init_fpu(void)
|
static inline int init_fpu(void)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
if (cpu_has_fpu) {
|
if (cpu_has_fpu) {
|
||||||
__own_fpu();
|
ret = __own_fpu();
|
||||||
_init_fpu();
|
if (!ret)
|
||||||
|
_init_fpu();
|
||||||
} else {
|
} else {
|
||||||
fpu_emulator_init_fpu();
|
fpu_emulator_init_fpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void save_fp(struct task_struct *tsk)
|
static inline void save_fp(struct task_struct *tsk)
|
||||||
|
|
|
@ -110,11 +110,12 @@ static inline struct thread_info *current_thread_info(void)
|
||||||
#define TIF_NOHZ 19 /* in adaptive nohz mode */
|
#define TIF_NOHZ 19 /* in adaptive nohz mode */
|
||||||
#define TIF_FIXADE 20 /* Fix address errors in software */
|
#define TIF_FIXADE 20 /* Fix address errors in software */
|
||||||
#define TIF_LOGADE 21 /* Log address errors to syslog */
|
#define TIF_LOGADE 21 /* Log address errors to syslog */
|
||||||
#define TIF_32BIT_REGS 22 /* also implies 16/32 fprs */
|
#define TIF_32BIT_REGS 22 /* 32-bit general purpose registers */
|
||||||
#define TIF_32BIT_ADDR 23 /* 32-bit address space (o32/n32) */
|
#define TIF_32BIT_ADDR 23 /* 32-bit address space (o32/n32) */
|
||||||
#define TIF_FPUBOUND 24 /* thread bound to FPU-full CPU set */
|
#define TIF_FPUBOUND 24 /* thread bound to FPU-full CPU set */
|
||||||
#define TIF_LOAD_WATCH 25 /* If set, load watch registers */
|
#define TIF_LOAD_WATCH 25 /* If set, load watch registers */
|
||||||
#define TIF_SYSCALL_TRACEPOINT 26 /* syscall tracepoint instrumentation */
|
#define TIF_SYSCALL_TRACEPOINT 26 /* syscall tracepoint instrumentation */
|
||||||
|
#define TIF_32BIT_FPREGS 27 /* 32-bit floating point registers */
|
||||||
#define TIF_SYSCALL_TRACE 31 /* syscall trace active */
|
#define TIF_SYSCALL_TRACE 31 /* syscall trace active */
|
||||||
|
|
||||||
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
|
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
|
||||||
|
@ -131,6 +132,7 @@ static inline struct thread_info *current_thread_info(void)
|
||||||
#define _TIF_32BIT_ADDR (1<<TIF_32BIT_ADDR)
|
#define _TIF_32BIT_ADDR (1<<TIF_32BIT_ADDR)
|
||||||
#define _TIF_FPUBOUND (1<<TIF_FPUBOUND)
|
#define _TIF_FPUBOUND (1<<TIF_FPUBOUND)
|
||||||
#define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH)
|
#define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH)
|
||||||
|
#define _TIF_32BIT_FPREGS (1<<TIF_32BIT_FPREGS)
|
||||||
#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
|
#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
|
||||||
|
|
||||||
#define _TIF_WORK_SYSCALL_ENTRY (_TIF_NOHZ | _TIF_SYSCALL_TRACE | \
|
#define _TIF_WORK_SYSCALL_ENTRY (_TIF_NOHZ | _TIF_SYSCALL_TRACE | \
|
||||||
|
|
|
@ -27,6 +27,18 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
|
||||||
typedef double elf_fpreg_t;
|
typedef double elf_fpreg_t;
|
||||||
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
|
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In order to be sure that we don't attempt to execute an O32 binary which
|
||||||
|
* requires 64 bit FP (FR=1) on a system which does not support it we refuse
|
||||||
|
* to execute any binary which has bits specified by the following macro set
|
||||||
|
* in its ELF header flags.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_MIPS_O32_FP64_SUPPORT
|
||||||
|
# define __MIPS_O32_FP64_MUST_BE_ZERO 0
|
||||||
|
#else
|
||||||
|
# define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is used to ensure we don't load something for the wrong architecture.
|
* This is used to ensure we don't load something for the wrong architecture.
|
||||||
*/
|
*/
|
||||||
|
@ -43,6 +55,8 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
|
||||||
__res = 0; \
|
__res = 0; \
|
||||||
if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
|
if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
|
||||||
((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
|
((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
|
||||||
|
__res = 0; \
|
||||||
|
if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \
|
||||||
__res = 0; \
|
__res = 0; \
|
||||||
\
|
\
|
||||||
__res; \
|
__res; \
|
||||||
|
|
|
@ -112,7 +112,7 @@ static inline unsigned long cpu_get_fpu_id(void)
|
||||||
unsigned long tmp, fpu_id;
|
unsigned long tmp, fpu_id;
|
||||||
|
|
||||||
tmp = read_c0_status();
|
tmp = read_c0_status();
|
||||||
__enable_fpu();
|
__enable_fpu(FPU_AS_IS);
|
||||||
fpu_id = read_32bit_cp1_register(CP1_REVISION);
|
fpu_id = read_32bit_cp1_register(CP1_REVISION);
|
||||||
write_c0_status(tmp);
|
write_c0_status(tmp);
|
||||||
return fpu_id;
|
return fpu_id;
|
||||||
|
|
|
@ -60,9 +60,6 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
|
||||||
|
|
||||||
/* New thread loses kernel privileges. */
|
/* New thread loses kernel privileges. */
|
||||||
status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK);
|
status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK);
|
||||||
#ifdef CONFIG_64BIT
|
|
||||||
status |= test_thread_flag(TIF_32BIT_REGS) ? 0 : ST0_FR;
|
|
||||||
#endif
|
|
||||||
status |= KU_USER;
|
status |= KU_USER;
|
||||||
regs->cp0_status = status;
|
regs->cp0_status = status;
|
||||||
clear_used_math();
|
clear_used_math();
|
||||||
|
|
|
@ -137,13 +137,13 @@ int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
|
||||||
if (cpu_has_mipsmt) {
|
if (cpu_has_mipsmt) {
|
||||||
unsigned int vpflags = dvpe();
|
unsigned int vpflags = dvpe();
|
||||||
flags = read_c0_status();
|
flags = read_c0_status();
|
||||||
__enable_fpu();
|
__enable_fpu(FPU_AS_IS);
|
||||||
__asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
|
__asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
|
||||||
write_c0_status(flags);
|
write_c0_status(flags);
|
||||||
evpe(vpflags);
|
evpe(vpflags);
|
||||||
} else {
|
} else {
|
||||||
flags = read_c0_status();
|
flags = read_c0_status();
|
||||||
__enable_fpu();
|
__enable_fpu(FPU_AS_IS);
|
||||||
__asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
|
__asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
|
||||||
write_c0_status(flags);
|
write_c0_status(flags);
|
||||||
}
|
}
|
||||||
|
@ -408,6 +408,7 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||||
/* Read the word at location addr in the USER area. */
|
/* Read the word at location addr in the USER area. */
|
||||||
case PTRACE_PEEKUSR: {
|
case PTRACE_PEEKUSR: {
|
||||||
struct pt_regs *regs;
|
struct pt_regs *regs;
|
||||||
|
fpureg_t *fregs;
|
||||||
unsigned long tmp = 0;
|
unsigned long tmp = 0;
|
||||||
|
|
||||||
regs = task_pt_regs(child);
|
regs = task_pt_regs(child);
|
||||||
|
@ -418,26 +419,28 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||||
tmp = regs->regs[addr];
|
tmp = regs->regs[addr];
|
||||||
break;
|
break;
|
||||||
case FPR_BASE ... FPR_BASE + 31:
|
case FPR_BASE ... FPR_BASE + 31:
|
||||||
if (tsk_used_math(child)) {
|
if (!tsk_used_math(child)) {
|
||||||
fpureg_t *fregs = get_fpu_regs(child);
|
/* FP not yet used */
|
||||||
|
tmp = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fregs = get_fpu_regs(child);
|
||||||
|
|
||||||
#ifdef CONFIG_32BIT
|
#ifdef CONFIG_32BIT
|
||||||
|
if (test_thread_flag(TIF_32BIT_FPREGS)) {
|
||||||
/*
|
/*
|
||||||
* The odd registers are actually the high
|
* The odd registers are actually the high
|
||||||
* order bits of the values stored in the even
|
* order bits of the values stored in the even
|
||||||
* registers - unless we're using r2k_switch.S.
|
* registers - unless we're using r2k_switch.S.
|
||||||
*/
|
*/
|
||||||
if (addr & 1)
|
if (addr & 1)
|
||||||
tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
|
tmp = fregs[(addr & ~1) - 32] >> 32;
|
||||||
else
|
else
|
||||||
tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
|
tmp = fregs[addr - 32];
|
||||||
#endif
|
break;
|
||||||
#ifdef CONFIG_64BIT
|
|
||||||
tmp = fregs[addr - FPR_BASE];
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
tmp = -1; /* FP not yet used */
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
tmp = fregs[addr - FPR_BASE];
|
||||||
break;
|
break;
|
||||||
case PC:
|
case PC:
|
||||||
tmp = regs->cp0_epc;
|
tmp = regs->cp0_epc;
|
||||||
|
@ -483,13 +486,13 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||||
if (cpu_has_mipsmt) {
|
if (cpu_has_mipsmt) {
|
||||||
unsigned int vpflags = dvpe();
|
unsigned int vpflags = dvpe();
|
||||||
flags = read_c0_status();
|
flags = read_c0_status();
|
||||||
__enable_fpu();
|
__enable_fpu(FPU_AS_IS);
|
||||||
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
|
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
|
||||||
write_c0_status(flags);
|
write_c0_status(flags);
|
||||||
evpe(vpflags);
|
evpe(vpflags);
|
||||||
} else {
|
} else {
|
||||||
flags = read_c0_status();
|
flags = read_c0_status();
|
||||||
__enable_fpu();
|
__enable_fpu(FPU_AS_IS);
|
||||||
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
|
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
|
||||||
write_c0_status(flags);
|
write_c0_status(flags);
|
||||||
}
|
}
|
||||||
|
@ -554,22 +557,25 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||||
child->thread.fpu.fcr31 = 0;
|
child->thread.fpu.fcr31 = 0;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_32BIT
|
#ifdef CONFIG_32BIT
|
||||||
/*
|
if (test_thread_flag(TIF_32BIT_FPREGS)) {
|
||||||
* The odd registers are actually the high order bits
|
/*
|
||||||
* of the values stored in the even registers - unless
|
* The odd registers are actually the high
|
||||||
* we're using r2k_switch.S.
|
* order bits of the values stored in the even
|
||||||
*/
|
* registers - unless we're using r2k_switch.S.
|
||||||
if (addr & 1) {
|
*/
|
||||||
fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
|
if (addr & 1) {
|
||||||
fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
|
fregs[(addr & ~1) - FPR_BASE] &=
|
||||||
} else {
|
0xffffffff;
|
||||||
fregs[addr - FPR_BASE] &= ~0xffffffffLL;
|
fregs[(addr & ~1) - FPR_BASE] |=
|
||||||
fregs[addr - FPR_BASE] |= data;
|
((u64)data) << 32;
|
||||||
|
} else {
|
||||||
|
fregs[addr - FPR_BASE] &= ~0xffffffffLL;
|
||||||
|
fregs[addr - FPR_BASE] |= data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_64BIT
|
|
||||||
fregs[addr - FPR_BASE] = data;
|
fregs[addr - FPR_BASE] = data;
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PC:
|
case PC:
|
||||||
|
|
|
@ -80,6 +80,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||||
/* Read the word at location addr in the USER area. */
|
/* Read the word at location addr in the USER area. */
|
||||||
case PTRACE_PEEKUSR: {
|
case PTRACE_PEEKUSR: {
|
||||||
struct pt_regs *regs;
|
struct pt_regs *regs;
|
||||||
|
fpureg_t *fregs;
|
||||||
unsigned int tmp;
|
unsigned int tmp;
|
||||||
|
|
||||||
regs = task_pt_regs(child);
|
regs = task_pt_regs(child);
|
||||||
|
@ -90,21 +91,25 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||||
tmp = regs->regs[addr];
|
tmp = regs->regs[addr];
|
||||||
break;
|
break;
|
||||||
case FPR_BASE ... FPR_BASE + 31:
|
case FPR_BASE ... FPR_BASE + 31:
|
||||||
if (tsk_used_math(child)) {
|
if (!tsk_used_math(child)) {
|
||||||
fpureg_t *fregs = get_fpu_regs(child);
|
/* FP not yet used */
|
||||||
|
tmp = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fregs = get_fpu_regs(child);
|
||||||
|
if (test_thread_flag(TIF_32BIT_FPREGS)) {
|
||||||
/*
|
/*
|
||||||
* The odd registers are actually the high
|
* The odd registers are actually the high
|
||||||
* order bits of the values stored in the even
|
* order bits of the values stored in the even
|
||||||
* registers - unless we're using r2k_switch.S.
|
* registers - unless we're using r2k_switch.S.
|
||||||
*/
|
*/
|
||||||
if (addr & 1)
|
if (addr & 1)
|
||||||
tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
|
tmp = fregs[(addr & ~1) - 32] >> 32;
|
||||||
else
|
else
|
||||||
tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
|
tmp = fregs[addr - 32];
|
||||||
} else {
|
break;
|
||||||
tmp = -1; /* FP not yet used */
|
|
||||||
}
|
}
|
||||||
|
tmp = fregs[addr - FPR_BASE];
|
||||||
break;
|
break;
|
||||||
case PC:
|
case PC:
|
||||||
tmp = regs->cp0_epc;
|
tmp = regs->cp0_epc;
|
||||||
|
@ -147,13 +152,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||||
if (cpu_has_mipsmt) {
|
if (cpu_has_mipsmt) {
|
||||||
unsigned int vpflags = dvpe();
|
unsigned int vpflags = dvpe();
|
||||||
flags = read_c0_status();
|
flags = read_c0_status();
|
||||||
__enable_fpu();
|
__enable_fpu(FPU_AS_IS);
|
||||||
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
|
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
|
||||||
write_c0_status(flags);
|
write_c0_status(flags);
|
||||||
evpe(vpflags);
|
evpe(vpflags);
|
||||||
} else {
|
} else {
|
||||||
flags = read_c0_status();
|
flags = read_c0_status();
|
||||||
__enable_fpu();
|
__enable_fpu(FPU_AS_IS);
|
||||||
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
|
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
|
||||||
write_c0_status(flags);
|
write_c0_status(flags);
|
||||||
}
|
}
|
||||||
|
@ -236,20 +241,24 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||||
sizeof(child->thread.fpu));
|
sizeof(child->thread.fpu));
|
||||||
child->thread.fpu.fcr31 = 0;
|
child->thread.fpu.fcr31 = 0;
|
||||||
}
|
}
|
||||||
/*
|
if (test_thread_flag(TIF_32BIT_FPREGS)) {
|
||||||
* The odd registers are actually the high order bits
|
/*
|
||||||
* of the values stored in the even registers - unless
|
* The odd registers are actually the high
|
||||||
* we're using r2k_switch.S.
|
* order bits of the values stored in the even
|
||||||
*/
|
* registers - unless we're using r2k_switch.S.
|
||||||
if (addr & 1) {
|
*/
|
||||||
fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
|
if (addr & 1) {
|
||||||
fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
|
fregs[(addr & ~1) - FPR_BASE] &=
|
||||||
} else {
|
0xffffffff;
|
||||||
fregs[addr - FPR_BASE] &= ~0xffffffffLL;
|
fregs[(addr & ~1) - FPR_BASE] |=
|
||||||
/* Must cast, lest sign extension fill upper
|
((u64)data) << 32;
|
||||||
bits! */
|
} else {
|
||||||
fregs[addr - FPR_BASE] |= (unsigned int)data;
|
fregs[addr - FPR_BASE] &= ~0xffffffffLL;
|
||||||
|
fregs[addr - FPR_BASE] |= data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
fregs[addr - FPR_BASE] = data;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PC:
|
case PC:
|
||||||
|
|
|
@ -35,7 +35,15 @@
|
||||||
LEAF(_save_fp_context)
|
LEAF(_save_fp_context)
|
||||||
cfc1 t1, fcr31
|
cfc1 t1, fcr31
|
||||||
|
|
||||||
#ifdef CONFIG_64BIT
|
#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
|
||||||
|
.set push
|
||||||
|
#ifdef CONFIG_MIPS32_R2
|
||||||
|
.set mips64r2
|
||||||
|
mfc0 t0, CP0_STATUS
|
||||||
|
sll t0, t0, 5
|
||||||
|
bgez t0, 1f # skip storing odd if FR=0
|
||||||
|
nop
|
||||||
|
#endif
|
||||||
/* Store the 16 odd double precision registers */
|
/* Store the 16 odd double precision registers */
|
||||||
EX sdc1 $f1, SC_FPREGS+8(a0)
|
EX sdc1 $f1, SC_FPREGS+8(a0)
|
||||||
EX sdc1 $f3, SC_FPREGS+24(a0)
|
EX sdc1 $f3, SC_FPREGS+24(a0)
|
||||||
|
@ -53,6 +61,7 @@ LEAF(_save_fp_context)
|
||||||
EX sdc1 $f27, SC_FPREGS+216(a0)
|
EX sdc1 $f27, SC_FPREGS+216(a0)
|
||||||
EX sdc1 $f29, SC_FPREGS+232(a0)
|
EX sdc1 $f29, SC_FPREGS+232(a0)
|
||||||
EX sdc1 $f31, SC_FPREGS+248(a0)
|
EX sdc1 $f31, SC_FPREGS+248(a0)
|
||||||
|
1: .set pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Store the 16 even double precision registers */
|
/* Store the 16 even double precision registers */
|
||||||
|
@ -82,7 +91,31 @@ LEAF(_save_fp_context)
|
||||||
LEAF(_save_fp_context32)
|
LEAF(_save_fp_context32)
|
||||||
cfc1 t1, fcr31
|
cfc1 t1, fcr31
|
||||||
|
|
||||||
EX sdc1 $f0, SC32_FPREGS+0(a0)
|
mfc0 t0, CP0_STATUS
|
||||||
|
sll t0, t0, 5
|
||||||
|
bgez t0, 1f # skip storing odd if FR=0
|
||||||
|
nop
|
||||||
|
|
||||||
|
/* Store the 16 odd double precision registers */
|
||||||
|
EX sdc1 $f1, SC32_FPREGS+8(a0)
|
||||||
|
EX sdc1 $f3, SC32_FPREGS+24(a0)
|
||||||
|
EX sdc1 $f5, SC32_FPREGS+40(a0)
|
||||||
|
EX sdc1 $f7, SC32_FPREGS+56(a0)
|
||||||
|
EX sdc1 $f9, SC32_FPREGS+72(a0)
|
||||||
|
EX sdc1 $f11, SC32_FPREGS+88(a0)
|
||||||
|
EX sdc1 $f13, SC32_FPREGS+104(a0)
|
||||||
|
EX sdc1 $f15, SC32_FPREGS+120(a0)
|
||||||
|
EX sdc1 $f17, SC32_FPREGS+136(a0)
|
||||||
|
EX sdc1 $f19, SC32_FPREGS+152(a0)
|
||||||
|
EX sdc1 $f21, SC32_FPREGS+168(a0)
|
||||||
|
EX sdc1 $f23, SC32_FPREGS+184(a0)
|
||||||
|
EX sdc1 $f25, SC32_FPREGS+200(a0)
|
||||||
|
EX sdc1 $f27, SC32_FPREGS+216(a0)
|
||||||
|
EX sdc1 $f29, SC32_FPREGS+232(a0)
|
||||||
|
EX sdc1 $f31, SC32_FPREGS+248(a0)
|
||||||
|
|
||||||
|
/* Store the 16 even double precision registers */
|
||||||
|
1: EX sdc1 $f0, SC32_FPREGS+0(a0)
|
||||||
EX sdc1 $f2, SC32_FPREGS+16(a0)
|
EX sdc1 $f2, SC32_FPREGS+16(a0)
|
||||||
EX sdc1 $f4, SC32_FPREGS+32(a0)
|
EX sdc1 $f4, SC32_FPREGS+32(a0)
|
||||||
EX sdc1 $f6, SC32_FPREGS+48(a0)
|
EX sdc1 $f6, SC32_FPREGS+48(a0)
|
||||||
|
@ -114,7 +147,16 @@ LEAF(_save_fp_context32)
|
||||||
*/
|
*/
|
||||||
LEAF(_restore_fp_context)
|
LEAF(_restore_fp_context)
|
||||||
EX lw t0, SC_FPC_CSR(a0)
|
EX lw t0, SC_FPC_CSR(a0)
|
||||||
#ifdef CONFIG_64BIT
|
|
||||||
|
#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
|
||||||
|
.set push
|
||||||
|
#ifdef CONFIG_MIPS32_R2
|
||||||
|
.set mips64r2
|
||||||
|
mfc0 t0, CP0_STATUS
|
||||||
|
sll t0, t0, 5
|
||||||
|
bgez t0, 1f # skip loading odd if FR=0
|
||||||
|
nop
|
||||||
|
#endif
|
||||||
EX ldc1 $f1, SC_FPREGS+8(a0)
|
EX ldc1 $f1, SC_FPREGS+8(a0)
|
||||||
EX ldc1 $f3, SC_FPREGS+24(a0)
|
EX ldc1 $f3, SC_FPREGS+24(a0)
|
||||||
EX ldc1 $f5, SC_FPREGS+40(a0)
|
EX ldc1 $f5, SC_FPREGS+40(a0)
|
||||||
|
@ -131,6 +173,7 @@ LEAF(_restore_fp_context)
|
||||||
EX ldc1 $f27, SC_FPREGS+216(a0)
|
EX ldc1 $f27, SC_FPREGS+216(a0)
|
||||||
EX ldc1 $f29, SC_FPREGS+232(a0)
|
EX ldc1 $f29, SC_FPREGS+232(a0)
|
||||||
EX ldc1 $f31, SC_FPREGS+248(a0)
|
EX ldc1 $f31, SC_FPREGS+248(a0)
|
||||||
|
1: .set pop
|
||||||
#endif
|
#endif
|
||||||
EX ldc1 $f0, SC_FPREGS+0(a0)
|
EX ldc1 $f0, SC_FPREGS+0(a0)
|
||||||
EX ldc1 $f2, SC_FPREGS+16(a0)
|
EX ldc1 $f2, SC_FPREGS+16(a0)
|
||||||
|
@ -157,7 +200,30 @@ LEAF(_restore_fp_context)
|
||||||
LEAF(_restore_fp_context32)
|
LEAF(_restore_fp_context32)
|
||||||
/* Restore an o32 sigcontext. */
|
/* Restore an o32 sigcontext. */
|
||||||
EX lw t0, SC32_FPC_CSR(a0)
|
EX lw t0, SC32_FPC_CSR(a0)
|
||||||
EX ldc1 $f0, SC32_FPREGS+0(a0)
|
|
||||||
|
mfc0 t0, CP0_STATUS
|
||||||
|
sll t0, t0, 5
|
||||||
|
bgez t0, 1f # skip loading odd if FR=0
|
||||||
|
nop
|
||||||
|
|
||||||
|
EX ldc1 $f1, SC32_FPREGS+8(a0)
|
||||||
|
EX ldc1 $f3, SC32_FPREGS+24(a0)
|
||||||
|
EX ldc1 $f5, SC32_FPREGS+40(a0)
|
||||||
|
EX ldc1 $f7, SC32_FPREGS+56(a0)
|
||||||
|
EX ldc1 $f9, SC32_FPREGS+72(a0)
|
||||||
|
EX ldc1 $f11, SC32_FPREGS+88(a0)
|
||||||
|
EX ldc1 $f13, SC32_FPREGS+104(a0)
|
||||||
|
EX ldc1 $f15, SC32_FPREGS+120(a0)
|
||||||
|
EX ldc1 $f17, SC32_FPREGS+136(a0)
|
||||||
|
EX ldc1 $f19, SC32_FPREGS+152(a0)
|
||||||
|
EX ldc1 $f21, SC32_FPREGS+168(a0)
|
||||||
|
EX ldc1 $f23, SC32_FPREGS+184(a0)
|
||||||
|
EX ldc1 $f25, SC32_FPREGS+200(a0)
|
||||||
|
EX ldc1 $f27, SC32_FPREGS+216(a0)
|
||||||
|
EX ldc1 $f29, SC32_FPREGS+232(a0)
|
||||||
|
EX ldc1 $f31, SC32_FPREGS+248(a0)
|
||||||
|
|
||||||
|
1: EX ldc1 $f0, SC32_FPREGS+0(a0)
|
||||||
EX ldc1 $f2, SC32_FPREGS+16(a0)
|
EX ldc1 $f2, SC32_FPREGS+16(a0)
|
||||||
EX ldc1 $f4, SC32_FPREGS+32(a0)
|
EX ldc1 $f4, SC32_FPREGS+32(a0)
|
||||||
EX ldc1 $f6, SC32_FPREGS+48(a0)
|
EX ldc1 $f6, SC32_FPREGS+48(a0)
|
||||||
|
|
|
@ -123,7 +123,7 @@
|
||||||
* Save a thread's fp context.
|
* Save a thread's fp context.
|
||||||
*/
|
*/
|
||||||
LEAF(_save_fp)
|
LEAF(_save_fp)
|
||||||
#ifdef CONFIG_64BIT
|
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
|
||||||
mfc0 t0, CP0_STATUS
|
mfc0 t0, CP0_STATUS
|
||||||
#endif
|
#endif
|
||||||
fpu_save_double a0 t0 t1 # clobbers t1
|
fpu_save_double a0 t0 t1 # clobbers t1
|
||||||
|
@ -134,7 +134,7 @@ LEAF(_save_fp)
|
||||||
* Restore a thread's fp context.
|
* Restore a thread's fp context.
|
||||||
*/
|
*/
|
||||||
LEAF(_restore_fp)
|
LEAF(_restore_fp)
|
||||||
#ifdef CONFIG_64BIT
|
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
|
||||||
mfc0 t0, CP0_STATUS
|
mfc0 t0, CP0_STATUS
|
||||||
#endif
|
#endif
|
||||||
fpu_restore_double a0 t0 t1 # clobbers t1
|
fpu_restore_double a0 t0 t1 # clobbers t1
|
||||||
|
@ -228,6 +228,47 @@ LEAF(_init_fpu)
|
||||||
mtc1 t1, $f29
|
mtc1 t1, $f29
|
||||||
mtc1 t1, $f30
|
mtc1 t1, $f30
|
||||||
mtc1 t1, $f31
|
mtc1 t1, $f31
|
||||||
|
|
||||||
|
#ifdef CONFIG_CPU_MIPS32_R2
|
||||||
|
.set push
|
||||||
|
.set mips64r2
|
||||||
|
sll t0, t0, 5 # is Status.FR set?
|
||||||
|
bgez t0, 1f # no: skip setting upper 32b
|
||||||
|
|
||||||
|
mthc1 t1, $f0
|
||||||
|
mthc1 t1, $f1
|
||||||
|
mthc1 t1, $f2
|
||||||
|
mthc1 t1, $f3
|
||||||
|
mthc1 t1, $f4
|
||||||
|
mthc1 t1, $f5
|
||||||
|
mthc1 t1, $f6
|
||||||
|
mthc1 t1, $f7
|
||||||
|
mthc1 t1, $f8
|
||||||
|
mthc1 t1, $f9
|
||||||
|
mthc1 t1, $f10
|
||||||
|
mthc1 t1, $f11
|
||||||
|
mthc1 t1, $f12
|
||||||
|
mthc1 t1, $f13
|
||||||
|
mthc1 t1, $f14
|
||||||
|
mthc1 t1, $f15
|
||||||
|
mthc1 t1, $f16
|
||||||
|
mthc1 t1, $f17
|
||||||
|
mthc1 t1, $f18
|
||||||
|
mthc1 t1, $f19
|
||||||
|
mthc1 t1, $f20
|
||||||
|
mthc1 t1, $f21
|
||||||
|
mthc1 t1, $f22
|
||||||
|
mthc1 t1, $f23
|
||||||
|
mthc1 t1, $f24
|
||||||
|
mthc1 t1, $f25
|
||||||
|
mthc1 t1, $f26
|
||||||
|
mthc1 t1, $f27
|
||||||
|
mthc1 t1, $f28
|
||||||
|
mthc1 t1, $f29
|
||||||
|
mthc1 t1, $f30
|
||||||
|
mthc1 t1, $f31
|
||||||
|
1: .set pop
|
||||||
|
#endif /* CONFIG_CPU_MIPS32_R2 */
|
||||||
#else
|
#else
|
||||||
.set mips3
|
.set mips3
|
||||||
dmtc1 t1, $f0
|
dmtc1 t1, $f0
|
||||||
|
|
|
@ -71,8 +71,9 @@ static int protected_save_fp_context(struct sigcontext __user *sc)
|
||||||
int err;
|
int err;
|
||||||
while (1) {
|
while (1) {
|
||||||
lock_fpu_owner();
|
lock_fpu_owner();
|
||||||
own_fpu_inatomic(1);
|
err = own_fpu_inatomic(1);
|
||||||
err = save_fp_context(sc); /* this might fail */
|
if (!err)
|
||||||
|
err = save_fp_context(sc); /* this might fail */
|
||||||
unlock_fpu_owner();
|
unlock_fpu_owner();
|
||||||
if (likely(!err))
|
if (likely(!err))
|
||||||
break;
|
break;
|
||||||
|
@ -91,8 +92,9 @@ static int protected_restore_fp_context(struct sigcontext __user *sc)
|
||||||
int err, tmp __maybe_unused;
|
int err, tmp __maybe_unused;
|
||||||
while (1) {
|
while (1) {
|
||||||
lock_fpu_owner();
|
lock_fpu_owner();
|
||||||
own_fpu_inatomic(0);
|
err = own_fpu_inatomic(0);
|
||||||
err = restore_fp_context(sc); /* this might fail */
|
if (!err)
|
||||||
|
err = restore_fp_context(sc); /* this might fail */
|
||||||
unlock_fpu_owner();
|
unlock_fpu_owner();
|
||||||
if (likely(!err))
|
if (likely(!err))
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -85,8 +85,9 @@ static int protected_save_fp_context32(struct sigcontext32 __user *sc)
|
||||||
int err;
|
int err;
|
||||||
while (1) {
|
while (1) {
|
||||||
lock_fpu_owner();
|
lock_fpu_owner();
|
||||||
own_fpu_inatomic(1);
|
err = own_fpu_inatomic(1);
|
||||||
err = save_fp_context32(sc); /* this might fail */
|
if (!err)
|
||||||
|
err = save_fp_context32(sc); /* this might fail */
|
||||||
unlock_fpu_owner();
|
unlock_fpu_owner();
|
||||||
if (likely(!err))
|
if (likely(!err))
|
||||||
break;
|
break;
|
||||||
|
@ -105,8 +106,9 @@ static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
|
||||||
int err, tmp __maybe_unused;
|
int err, tmp __maybe_unused;
|
||||||
while (1) {
|
while (1) {
|
||||||
lock_fpu_owner();
|
lock_fpu_owner();
|
||||||
own_fpu_inatomic(0);
|
err = own_fpu_inatomic(0);
|
||||||
err = restore_fp_context32(sc); /* this might fail */
|
if (!err)
|
||||||
|
err = restore_fp_context32(sc); /* this might fail */
|
||||||
unlock_fpu_owner();
|
unlock_fpu_owner();
|
||||||
if (likely(!err))
|
if (likely(!err))
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1080,7 +1080,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
|
||||||
unsigned long old_epc, old31;
|
unsigned long old_epc, old31;
|
||||||
unsigned int opcode;
|
unsigned int opcode;
|
||||||
unsigned int cpid;
|
unsigned int cpid;
|
||||||
int status;
|
int status, err;
|
||||||
unsigned long __maybe_unused flags;
|
unsigned long __maybe_unused flags;
|
||||||
|
|
||||||
prev_state = exception_enter();
|
prev_state = exception_enter();
|
||||||
|
@ -1153,19 +1153,19 @@ asmlinkage void do_cpu(struct pt_regs *regs)
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
if (used_math()) /* Using the FPU again. */
|
if (used_math()) /* Using the FPU again. */
|
||||||
own_fpu(1);
|
err = own_fpu(1);
|
||||||
else { /* First time FPU user. */
|
else { /* First time FPU user. */
|
||||||
init_fpu();
|
err = init_fpu();
|
||||||
set_used_math();
|
set_used_math();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!raw_cpu_has_fpu) {
|
if (!raw_cpu_has_fpu || err) {
|
||||||
int sig;
|
int sig;
|
||||||
void __user *fault_addr = NULL;
|
void __user *fault_addr = NULL;
|
||||||
sig = fpu_emulator_cop1Handler(regs,
|
sig = fpu_emulator_cop1Handler(regs,
|
||||||
¤t->thread.fpu,
|
¤t->thread.fpu,
|
||||||
0, &fault_addr);
|
0, &fault_addr);
|
||||||
if (!process_fpemu_return(sig, fault_addr))
|
if (!process_fpemu_return(sig, fault_addr) && !err)
|
||||||
mt_ase_fp_affinity();
|
mt_ase_fp_affinity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -859,20 +859,20 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
|
||||||
* In the Linux kernel, we support selection of FPR format on the
|
* In the Linux kernel, we support selection of FPR format on the
|
||||||
* basis of the Status.FR bit. If an FPU is not present, the FR bit
|
* basis of the Status.FR bit. If an FPU is not present, the FR bit
|
||||||
* is hardwired to zero, which would imply a 32-bit FPU even for
|
* is hardwired to zero, which would imply a 32-bit FPU even for
|
||||||
* 64-bit CPUs so we rather look at TIF_32BIT_REGS.
|
* 64-bit CPUs so we rather look at TIF_32BIT_FPREGS.
|
||||||
* FPU emu is slow and bulky and optimizing this function offers fairly
|
* FPU emu is slow and bulky and optimizing this function offers fairly
|
||||||
* sizeable benefits so we try to be clever and make this function return
|
* sizeable benefits so we try to be clever and make this function return
|
||||||
* a constant whenever possible, that is on 64-bit kernels without O32
|
* a constant whenever possible, that is on 64-bit kernels without O32
|
||||||
* compatibility enabled and on 32-bit kernels.
|
* compatibility enabled and on 32-bit without 64-bit FPU support.
|
||||||
*/
|
*/
|
||||||
static inline int cop1_64bit(struct pt_regs *xcp)
|
static inline int cop1_64bit(struct pt_regs *xcp)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32)
|
#if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32)
|
||||||
return 1;
|
return 1;
|
||||||
#elif defined(CONFIG_64BIT) && defined(CONFIG_MIPS32_O32)
|
#elif defined(CONFIG_32BIT) && !defined(CONFIG_MIPS_O32_FP64_SUPPORT)
|
||||||
return !test_thread_flag(TIF_32BIT_REGS);
|
|
||||||
#else
|
|
||||||
return 0;
|
return 0;
|
||||||
|
#else
|
||||||
|
return !test_thread_flag(TIF_32BIT_FPREGS);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,8 +89,9 @@ int fpu_emulator_save_context32(struct sigcontext32 __user *sc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
|
||||||
|
|
||||||
for (i = 0; i < 32; i+=2) {
|
for (i = 0; i < 32; i += inc) {
|
||||||
err |=
|
err |=
|
||||||
__put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
|
__put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
|
||||||
}
|
}
|
||||||
|
@ -103,8 +104,9 @@ int fpu_emulator_restore_context32(struct sigcontext32 __user *sc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
|
||||||
|
|
||||||
for (i = 0; i < 32; i+=2) {
|
for (i = 0; i < 32; i += inc) {
|
||||||
err |=
|
err |=
|
||||||
__get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
|
__get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue