Commit ed32949e authored by Vincent Chen's avatar Vincent Chen Committed by Greentime Hu

nds32: Avoid IEX status being incorrectly modified

In order for kernel to capture each denormalized output, the UDF
trapping enable bit is always raised in $fpcsr. Because underflow case will
issue not an underflow exception but also an inexact exception, it causes
that the IEX, IEX cumulative exception, flag in $fpcsr to be raised in each
denormalized output handling. To make the emulation transparent to the
user, the emulator needs to clear the IEX flag in $fpcsr if the result is a
denormalized number. However, if the IEX flag has been raised before this
floating point emulation, this cleanup may be incorrect. To avoid the IEX
flags in $fpcsr be raised in each denormalized output handling, the IEX
trap shall be always enabled.
Signed-off-by: default avatarVincent Chen <vincentc@andestech.com>
Acked-by: default avatarGreentime Hu <greentime@andestech.com>
Signed-off-by: default avatarGreentime Hu <greentime@andestech.com>
parent 8183db10
...@@ -937,7 +937,7 @@ ...@@ -937,7 +937,7 @@
#define FPCSR_mskDNIT ( 0x1 << FPCSR_offDNIT ) #define FPCSR_mskDNIT ( 0x1 << FPCSR_offDNIT )
#define FPCSR_mskRIT ( 0x1 << FPCSR_offRIT ) #define FPCSR_mskRIT ( 0x1 << FPCSR_offRIT )
#define FPCSR_mskALL (FPCSR_mskIVO | FPCSR_mskDBZ | FPCSR_mskOVF | FPCSR_mskUDF | FPCSR_mskIEX) #define FPCSR_mskALL (FPCSR_mskIVO | FPCSR_mskDBZ | FPCSR_mskOVF | FPCSR_mskUDF | FPCSR_mskIEX)
#define FPCSR_mskALLE_NO_UDFE (FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE | FPCSR_mskIEXE) #define FPCSR_mskALLE_NO_UDF_IEXE (FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE)
#define FPCSR_mskALLE (FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE | FPCSR_mskUDFE | FPCSR_mskIEXE) #define FPCSR_mskALLE (FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE | FPCSR_mskUDFE | FPCSR_mskIEXE)
#define FPCSR_mskALLT (FPCSR_mskIVOT | FPCSR_mskDBZT | FPCSR_mskOVFT | FPCSR_mskUDFT | FPCSR_mskIEXT |FPCSR_mskDNIT | FPCSR_mskRIT) #define FPCSR_mskALLT (FPCSR_mskIVOT | FPCSR_mskDBZT | FPCSR_mskOVFT | FPCSR_mskUDFT | FPCSR_mskIEXT |FPCSR_mskDNIT | FPCSR_mskRIT)
......
...@@ -36,7 +36,7 @@ extern int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu); ...@@ -36,7 +36,7 @@ extern int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu);
* enabled by default and kerenl will re-execute it by fpu emulator * enabled by default and kerenl will re-execute it by fpu emulator
* when getting underflow exception. * when getting underflow exception.
*/ */
#define FPCSR_INIT FPCSR_mskUDFE #define FPCSR_INIT (FPCSR_mskUDFE | FPCSR_mskIEXE)
#else #else
#define FPCSR_INIT 0x0UL #define FPCSR_INIT 0x0UL
#endif #endif
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
asmlinkage long sys_cacheflush(unsigned long addr, unsigned long len, unsigned int op); asmlinkage long sys_cacheflush(unsigned long addr, unsigned long len, unsigned int op);
asmlinkage long sys_fadvise64_64_wrapper(int fd, int advice, loff_t offset, loff_t len); asmlinkage long sys_fadvise64_64_wrapper(int fd, int advice, loff_t offset, loff_t len);
asmlinkage long sys_rt_sigreturn_wrapper(void); asmlinkage long sys_rt_sigreturn_wrapper(void);
asmlinkage long sys_udftrap(int option); asmlinkage long sys_fp_udfiex_crtl(int cmd, int act);
#include <asm-generic/syscalls.h> #include <asm-generic/syscalls.h>
......
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2005-2019 Andes Technology Corporation */
#ifndef _FP_UDF_IEX_CRTL_H
#define _FP_UDF_IEX_CRTL_H
/*
* The cmd list of sys_fp_udfiex_crtl()
*/
/* Disable UDF or IEX trap based on the content of parameter act */
#define DISABLE_UDF_IEX_TRAP 0
/* Enable UDF or IEX trap based on the content of parameter act */
#define ENABLE_UDF_IEX_TRAP 1
/* Get current status of UDF and IEX trap */
#define GET_UDF_IEX_TRAP 2
#endif /* _FP_UDF_IEX_CRTL_H */
...@@ -13,14 +13,24 @@ struct fpu_struct { ...@@ -13,14 +13,24 @@ struct fpu_struct {
unsigned long long fd_regs[32]; unsigned long long fd_regs[32];
unsigned long fpcsr; unsigned long fpcsr;
/* /*
* UDF_trap is used to recognize whether underflow trap is enabled * When CONFIG_SUPPORT_DENORMAL_ARITHMETIC is defined, kernel prevents
* or not. When UDF_trap == 1, this process will be traped and then * hardware from treating the denormalized output as an underflow case
* get a SIGFPE signal when encountering an underflow exception. * and rounding it to a normal number. Hence kernel enables the UDF and
* UDF_trap is only modified through setfputrap syscall. Therefore, * IEX trap in the fpcsr register to step in the calculation.
* UDF_trap needn't be saved or loaded to context in each context * However, the UDF and IEX trap enable bit in $fpcsr also lose
* switch. * their use.
*
* UDF_IEX_trap replaces the feature of UDF and IEX trap enable bit in
* $fpcsr to control the trap of underflow and inexact. The bit filed
* of UDF_IEX_trap is the same as $fpcsr, 10th bit is used to enable UDF
* exception trapping and 11th bit is used to enable IEX exception
* trapping.
*
* UDF_IEX_trap is only modified through fp_udfiex_crtl syscall.
* Therefore, UDF_IEX_trap needn't be saved and restored in each
* context switch.
*/ */
unsigned long UDF_trap; unsigned long UDF_IEX_trap;
}; };
struct zol_struct { struct zol_struct {
......
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2005-2018 Andes Technology Corporation */
#ifndef _ASM_SETFPUTRAP
#define _ASM_SETFPUTRAP
/*
* Options for setfputrap system call
*/
#define DISABLE_UDFTRAP 0 /* disable underflow exception trap */
#define ENABLE_UDFTRAP 1 /* enable undeflos exception trap */
#define GET_UDFTRAP 2 /* only get undeflos exception trap status */
#endif /* _ASM_CACHECTL */
...@@ -11,6 +11,6 @@ ...@@ -11,6 +11,6 @@
/* Additional NDS32 specific syscalls. */ /* Additional NDS32 specific syscalls. */
#define __NR_cacheflush (__NR_arch_specific_syscall) #define __NR_cacheflush (__NR_arch_specific_syscall)
#define __NR_udftrap (__NR_arch_specific_syscall + 1) #define __NR_fp_udfiex_crtl (__NR_arch_specific_syscall + 1)
__SYSCALL(__NR_cacheflush, sys_cacheflush) __SYSCALL(__NR_cacheflush, sys_cacheflush)
__SYSCALL(__NR_udftrap, sys_udftrap) __SYSCALL(__NR_fp_udfiex_crtl, sys_fp_udfiex_crtl)
...@@ -14,7 +14,7 @@ const struct fpu_struct init_fpuregs = { ...@@ -14,7 +14,7 @@ const struct fpu_struct init_fpuregs = {
.fd_regs = {[0 ... 31] = sNAN64}, .fd_regs = {[0 ... 31] = sNAN64},
.fpcsr = FPCSR_INIT, .fpcsr = FPCSR_INIT,
#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
.UDF_trap = 0 .UDF_IEX_trap = 0
#endif #endif
}; };
...@@ -178,7 +178,7 @@ inline void do_fpu_context_switch(struct pt_regs *regs) ...@@ -178,7 +178,7 @@ inline void do_fpu_context_switch(struct pt_regs *regs)
/* First time FPU user. */ /* First time FPU user. */
load_fpu(&init_fpuregs); load_fpu(&init_fpuregs);
#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
current->thread.fpu.UDF_trap = init_fpuregs.UDF_trap; current->thread.fpu.UDF_IEX_trap = init_fpuregs.UDF_IEX_trap;
#endif #endif
set_used_math(); set_used_math();
} }
...@@ -206,7 +206,7 @@ inline void handle_fpu_exception(struct pt_regs *regs) ...@@ -206,7 +206,7 @@ inline void handle_fpu_exception(struct pt_regs *regs)
unsigned int fpcsr; unsigned int fpcsr;
int si_code = 0, si_signo = SIGFPE; int si_code = 0, si_signo = SIGFPE;
#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
unsigned long redo_except = FPCSR_mskDNIT|FPCSR_mskUDFT; unsigned long redo_except = FPCSR_mskDNIT|FPCSR_mskUDFT|FPCSR_mskIEXT;
#else #else
unsigned long redo_except = FPCSR_mskDNIT; unsigned long redo_except = FPCSR_mskDNIT;
#endif #endif
...@@ -215,21 +215,18 @@ inline void handle_fpu_exception(struct pt_regs *regs) ...@@ -215,21 +215,18 @@ inline void handle_fpu_exception(struct pt_regs *regs)
fpcsr = current->thread.fpu.fpcsr; fpcsr = current->thread.fpu.fpcsr;
if (fpcsr & redo_except) { if (fpcsr & redo_except) {
#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
if (fpcsr & FPCSR_mskUDFT)
current->thread.fpu.fpcsr &= ~FPCSR_mskIEX;
#endif
si_signo = do_fpuemu(regs, &current->thread.fpu); si_signo = do_fpuemu(regs, &current->thread.fpu);
fpcsr = current->thread.fpu.fpcsr; fpcsr = current->thread.fpu.fpcsr;
if (!si_signo) if (!si_signo) {
current->thread.fpu.fpcsr &= ~(redo_except);
goto done; goto done;
}
} else if (fpcsr & FPCSR_mskRIT) { } else if (fpcsr & FPCSR_mskRIT) {
if (!user_mode(regs)) if (!user_mode(regs))
do_exit(SIGILL); do_exit(SIGILL);
si_signo = SIGILL; si_signo = SIGILL;
} }
switch (si_signo) { switch (si_signo) {
case SIGFPE: case SIGFPE:
fill_sigfpe_signo(fpcsr, &si_code); fill_sigfpe_signo(fpcsr, &si_code);
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
#include <asm/cachectl.h> #include <asm/cachectl.h>
#include <asm/proc-fns.h> #include <asm/proc-fns.h>
#include <asm/udftrap.h>
#include <asm/fpu.h> #include <asm/fpu.h>
#include <asm/fp_udfiex_crtl.h>
SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags, unsigned long, prot, unsigned long, flags,
...@@ -51,31 +51,33 @@ SYSCALL_DEFINE3(cacheflush, unsigned int, start, unsigned int, end, int, cache) ...@@ -51,31 +51,33 @@ SYSCALL_DEFINE3(cacheflush, unsigned int, start, unsigned int, end, int, cache)
return 0; return 0;
} }
SYSCALL_DEFINE1(udftrap, int, option) SYSCALL_DEFINE2(fp_udfiex_crtl, unsigned int, cmd, unsigned int, act)
{ {
#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
int old_udftrap; int old_udf_iex;
if (!used_math()) { if (!used_math()) {
load_fpu(&init_fpuregs); load_fpu(&init_fpuregs);
current->thread.fpu.UDF_trap = init_fpuregs.UDF_trap; current->thread.fpu.UDF_IEX_trap = init_fpuregs.UDF_IEX_trap;
set_used_math(); set_used_math();
} }
old_udftrap = current->thread.fpu.UDF_trap; old_udf_iex = current->thread.fpu.UDF_IEX_trap;
switch (option) { act &= (FPCSR_mskUDFE | FPCSR_mskIEXE);
case DISABLE_UDFTRAP:
current->thread.fpu.UDF_trap = 0; switch (cmd) {
case DISABLE_UDF_IEX_TRAP:
current->thread.fpu.UDF_IEX_trap &= ~act;
break; break;
case ENABLE_UDFTRAP: case ENABLE_UDF_IEX_TRAP:
current->thread.fpu.UDF_trap = FPCSR_mskUDFE; current->thread.fpu.UDF_IEX_trap |= act;
break; break;
case GET_UDFTRAP: case GET_UDF_IEX_TRAP:
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
return old_udftrap; return old_udf_iex;
#else #else
return -ENOTSUPP; return -ENOTSUPP;
#endif #endif
......
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