Skip to content

Commit

Permalink
openrisc: Support floating point user api
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
stffrdhrn committed Apr 26, 2023
1 parent 63d7f9f commit 2726765
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 6 deletions.
3 changes: 1 addition & 2 deletions arch/openrisc/include/uapi/asm/elf.h
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions arch/openrisc/include/uapi/asm/ptrace.h
Expand Up @@ -30,6 +30,10 @@ struct user_regs_struct {
unsigned long pc;
unsigned long sr;
};

struct __or1k_fpu_state {
unsigned long fpcsr;
};
#endif


Expand Down
1 change: 1 addition & 0 deletions arch/openrisc/include/uapi/asm/sigcontext.h
Expand Up @@ -28,6 +28,7 @@

struct sigcontext {
struct user_regs_struct regs; /* needs to be first */
struct __or1k_fpu_state fpu;
unsigned long oldmask;
};

Expand Down
11 changes: 9 additions & 2 deletions arch/openrisc/kernel/entry.S
Expand Up @@ -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 ]------------------------------------------ */

Expand Down
4 changes: 2 additions & 2 deletions arch/openrisc/kernel/head.S
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions arch/openrisc/kernel/signal.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
22 changes: 22 additions & 0 deletions arch/openrisc/kernel/traps.c
Expand Up @@ -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);
Expand Down

0 comments on commit 2726765

Please sign in to comment.