openrisc: Support floating point user api
authorStafford Horne <shorne@gmail.com>
Fri, 14 Apr 2023 07:27:51 +0000 (08:27 +0100)
committerStafford Horne <shorne@gmail.com>
Wed, 26 Apr 2023 14:08:06 +0000 (15:08 +0100)
Add support for handling floating point exceptions and forwarding the
SIGFPE signal to processes.  Also, add fpu state to sigcontext.

Signed-off-by: Stafford Horne <shorne@gmail.com>
arch/openrisc/include/uapi/asm/elf.h
arch/openrisc/include/uapi/asm/ptrace.h
arch/openrisc/include/uapi/asm/sigcontext.h
arch/openrisc/kernel/entry.S
arch/openrisc/kernel/head.S
arch/openrisc/kernel/signal.c
arch/openrisc/kernel/traps.c

index e892d5061685267f3107fd2c6846d616bf544f53..6868f81c281ecb5676d1df2955f3f2f48e5decc9 100644 (file)
@@ -53,8 +53,7 @@ typedef unsigned long elf_greg_t;
 #define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
-/* A placeholder; OR32 does not have fp support yes, so no fp regs for now.  */
-typedef unsigned long elf_fpregset_t;
+typedef struct __or1k_fpu_state elf_fpregset_t;
 
 /* EM_OPENRISC is defined in linux/elf-em.h */
 #define EM_OR32         0x8472
index d4fab268f6aa0ff3ea489eaa5e1f69daace67533..a77cc9915ca8fed0e5e4bc1941b469c865ff56db 100644 (file)
@@ -30,6 +30,10 @@ struct user_regs_struct {
        unsigned long pc;
        unsigned long sr;
 };
+
+struct __or1k_fpu_state {
+       unsigned long fpcsr;
+};
 #endif
 
 
index 8ab775fc3450671d0c980724f2e00e6be682077f..ca585e4af6b8eac431e100b229e938e49d274c35 100644 (file)
@@ -28,6 +28,7 @@
 
 struct sigcontext {
        struct user_regs_struct regs;  /* needs to be first */
+       struct __or1k_fpu_state fpu;
        unsigned long oldmask;
 };
 
index c7b47e571220e88c70cbab07cef8c1fff7a7af04..c9f48e750b72b5ce0ffe1922754dac85963bacd5 100644 (file)
@@ -848,9 +848,16 @@ _syscall_badsys:
 
 /******* END SYSCALL HANDLING *******/
 
-/* ---[ 0xd00: Trap exception ]------------------------------------------ */
+/* ---[ 0xd00: Floating Point exception ]-------------------------------- */
 
-UNHANDLED_EXCEPTION(_vector_0xd00,0xd00)
+EXCEPTION_ENTRY(_fpe_trap_handler)
+       CLEAR_LWA_FLAG(r3)
+       /* r4: EA of fault (set by EXCEPTION_HANDLE) */
+       l.jal   do_fpe_trap
+        l.addi  r3,r1,0 /* pt_regs */
+
+       l.j     _ret_from_exception
+        l.nop
 
 /* ---[ 0xe00: Trap exception ]------------------------------------------ */
 
index e11699f3d6bdca97386ce8249b567f0b11a7a20b..439e00f81e5dde182244d7e90756157c8fc02b7f 100644 (file)
@@ -424,9 +424,9 @@ _dispatch_do_ipage_fault:
     .org 0xc00
        EXCEPTION_HANDLE(_sys_call_handler)
 
-/* ---[ 0xd00: Trap exception ]------------------------------------------ */
+/* ---[ 0xd00: Floating point exception ]--------------------------------- */
     .org 0xd00
-       UNHANDLED_EXCEPTION(_vector_0xd00)
+       EXCEPTION_HANDLE(_fpe_trap_handler)
 
 /* ---[ 0xe00: Trap exception ]------------------------------------------ */
     .org 0xe00
index 80f69740c731d3196d0956e821e07ed5a9248068..4664a18f0787d4e40e86061831aed605a82846c9 100644 (file)
@@ -50,6 +50,7 @@ static int restore_sigcontext(struct pt_regs *regs,
        err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long));
        err |= __copy_from_user(&regs->pc, &sc->regs.pc, sizeof(unsigned long));
        err |= __copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long));
+       err |= __copy_from_user(&regs->fpcsr, &sc->fpu.fpcsr, sizeof(unsigned long));
 
        /* make sure the SM-bit is cleared so user-mode cannot fool us */
        regs->sr &= ~SPR_SR_SM;
@@ -112,6 +113,7 @@ static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
        err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long));
        err |= __copy_to_user(&sc->regs.pc, &regs->pc, sizeof(unsigned long));
        err |= __copy_to_user(&sc->regs.sr, &regs->sr, sizeof(unsigned long));
+       err |= __copy_to_user(&sc->fpu.fpcsr, &regs->fpcsr, sizeof(unsigned long));
 
        return err;
 }
index f5bbe6b55849a3db1def4131cf622e7241cb501d..0aa6b07efda1b34cc2de4c2d181f001019be2d92 100644 (file)
@@ -243,6 +243,28 @@ asmlinkage void unhandled_exception(struct pt_regs *regs, int ea, int vector)
        die("Oops", regs, 9);
 }
 
+asmlinkage void do_fpe_trap(struct pt_regs *regs, unsigned long address)
+{
+       int code = FPE_FLTUNK;
+       unsigned long fpcsr = regs->fpcsr;
+
+       if (fpcsr & SPR_FPCSR_IVF)
+               code = FPE_FLTINV;
+       else if (fpcsr & SPR_FPCSR_OVF)
+               code = FPE_FLTOVF;
+       else if (fpcsr & SPR_FPCSR_UNF)
+               code = FPE_FLTUND;
+       else if (fpcsr & SPR_FPCSR_DZF)
+               code = FPE_FLTDIV;
+       else if (fpcsr & SPR_FPCSR_IXF)
+               code = FPE_FLTRES;
+
+       /* Clear all flags */
+       regs->fpcsr &= ~SPR_FPCSR_ALLF;
+
+       force_sig_fault(SIGFPE, code, (void __user *)regs->pc);
+}
+
 asmlinkage void do_trap(struct pt_regs *regs, unsigned long address)
 {
        force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc);