diff options
author | Vincent Chen <vincentc@andestech.com> | 2018-11-22 11:14:35 +0800 |
---|---|---|
committer | Greentime Hu <greentime@andestech.com> | 2018-11-22 18:13:21 +0800 |
commit | 1ac832509f2ea1b566f0c06f98f308f58b03d098 (patch) | |
tree | 080dcfd5832558823072d3fd4de51df32d96ef51 /arch/nds32/kernel | |
parent | e46bf83c1864a20f9dd17d597ec9be18ed05add8 (diff) | |
download | linux-1ac832509f2ea1b566f0c06f98f308f58b03d098.tar.gz linux-1ac832509f2ea1b566f0c06f98f308f58b03d098.tar.bz2 linux-1ac832509f2ea1b566f0c06f98f308f58b03d098.zip |
nds32: Support FP emulation
The Andes FPU coprocessor does not support denormalized number handling.
According to the specification, FPU generates a denorm input exception
that requires the kernel to deal with this instrution operation when it
encounters denormalized operands. Hence an nds32 FPU ISA emulator in the
kernel is required to meet requirement.
Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Nickhu <nickhu@andestech.com>
Acked-by: Greentime Hu <greentime@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
Diffstat (limited to 'arch/nds32/kernel')
-rw-r--r-- | arch/nds32/kernel/fpu.c | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/arch/nds32/kernel/fpu.c b/arch/nds32/kernel/fpu.c index e55a1e190e97..2942df6f93e6 100644 --- a/arch/nds32/kernel/fpu.c +++ b/arch/nds32/kernel/fpu.c @@ -183,10 +183,10 @@ inline void fill_sigfpe_signo(unsigned int fpcsr, int *signo) { if (fpcsr & FPCSR_mskOVFT) *signo = FPE_FLTOVF; - else if (fpcsr & FPCSR_mskUDFT) - *signo = FPE_FLTUND; else if (fpcsr & FPCSR_mskIVOT) *signo = FPE_FLTINV; + else if (fpcsr & FPCSR_mskUDFT) + *signo = FPE_FLTUND; else if (fpcsr & FPCSR_mskDBZT) *signo = FPE_FLTDIV; else if (fpcsr & FPCSR_mskIEXT) @@ -201,16 +201,37 @@ inline void handle_fpu_exception(struct pt_regs *regs) lose_fpu(); fpcsr = current->thread.fpu.fpcsr; - if (fpcsr & FPCSR_mskRIT) { + if (fpcsr & FPCSR_mskDNIT) { + si_signo = do_fpuemu(regs, ¤t->thread.fpu); + fpcsr = current->thread.fpu.fpcsr; + if (!si_signo) + goto done; + } else if (fpcsr & FPCSR_mskRIT) { if (!user_mode(regs)) do_exit(SIGILL); si_signo = SIGILL; + } + + + switch (si_signo) { + case SIGFPE: + fill_sigfpe_signo(fpcsr, &si_code); + break; + case SIGILL: show_regs(regs); si_code = ILL_COPROC; - } else - fill_sigfpe_signo(fpcsr, &si_code); + break; + case SIGBUS: + si_code = BUS_ADRERR; + break; + default: + break; + } + force_sig_fault(si_signo, si_code, (void __user *)instruction_pointer(regs), current); +done: + own_fpu(); } bool do_fpu_exception(unsigned int subtype, struct pt_regs *regs) |