summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2021-01-09 13:14:02 +0000
committerkettenis <kettenis@openbsd.org>2021-01-09 13:14:02 +0000
commit068793ccd4d9da0f69bf5536a9c727065f20b05d (patch)
tree3a6af3e88fd02d6f4a0061e7ebc4b4425c78f22e
parentadd a comma to previous; (diff)
downloadwireguard-openbsd-068793ccd4d9da0f69bf5536a9c727065f20b05d.tar.xz
wireguard-openbsd-068793ccd4d9da0f69bf5536a9c727065f20b05d.zip
Enable support for floating-point exceptions. We always run in "precise"
mode. On modern processors (POWER8 and later) there is no performance penalty for this as long as exceptions are disabled in the FPSCR (which is the default). This way we don't have to implement an architecture-dependent system call to set the mode, as it can only be done by the kernel. With help from gkoehler@ ok gkoehler@
-rw-r--r--sys/arch/powerpc64/include/fpu.h2
-rw-r--r--sys/arch/powerpc64/include/pcb.h4
-rw-r--r--sys/arch/powerpc64/include/psl.h4
-rw-r--r--sys/arch/powerpc64/powerpc64/fpu.c30
-rw-r--r--sys/arch/powerpc64/powerpc64/machdep.c18
-rw-r--r--sys/arch/powerpc64/powerpc64/process_machdep.c18
-rw-r--r--sys/arch/powerpc64/powerpc64/trap.c12
-rw-r--r--sys/arch/powerpc64/powerpc64/vm_machdep.c11
8 files changed, 68 insertions, 31 deletions
diff --git a/sys/arch/powerpc64/include/fpu.h b/sys/arch/powerpc64/include/fpu.h
index 026f5ba0a3d..7c212e77adc 100644
--- a/sys/arch/powerpc64/include/fpu.h
+++ b/sys/arch/powerpc64/include/fpu.h
@@ -6,6 +6,8 @@
void save_vsx(struct proc *);
void restore_vsx(struct proc *);
+int fpu_sigcode(struct proc *);
+
#endif
#endif /* _MACHINE_FPU_H_ */
diff --git a/sys/arch/powerpc64/include/pcb.h b/sys/arch/powerpc64/include/pcb.h
index 3bc8295af49..7c22ae598a6 100644
--- a/sys/arch/powerpc64/include/pcb.h
+++ b/sys/arch/powerpc64/include/pcb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pcb.h,v 1.7 2020/08/17 16:55:41 kettenis Exp $ */
+/* $OpenBSD: pcb.h,v 1.8 2021/01/09 13:14:02 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -25,7 +25,7 @@
struct pcb {
register_t pcb_sp;
u_int pcb_flags;
-#define PCB_FP 0x000000001
+#define PCB_FPU 0x000000001
#define PCB_VEC 0x000000002
#define PCB_VSX 0x000000004
struct slb pcb_slb[32];
diff --git a/sys/arch/powerpc64/include/psl.h b/sys/arch/powerpc64/include/psl.h
index efce955c24b..6d559b5e9ec 100644
--- a/sys/arch/powerpc64/include/psl.h
+++ b/sys/arch/powerpc64/include/psl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: psl.h,v 1.2 2020/05/22 15:07:47 kettenis Exp $ */
+/* $OpenBSD: psl.h,v 1.3 2021/01/09 13:14:02 kettenis Exp $ */
/*-
* SPDX-License-Identifier: BSD-4-Clause
@@ -83,4 +83,6 @@
#define PSL_FE_PREC (PSL_FE0 | PSL_FE1) /* precise */
#define PSL_FE_DFLT PSL_FE_DIS /* default == none */
+#define PSL_FPU (PSL_FP | PSL_FE_PREC)
+
#endif /* _MACHINE_PSL_H_ */
diff --git a/sys/arch/powerpc64/powerpc64/fpu.c b/sys/arch/powerpc64/powerpc64/fpu.c
index 23705aee400..07ac84f77d0 100644
--- a/sys/arch/powerpc64/powerpc64/fpu.c
+++ b/sys/arch/powerpc64/powerpc64/fpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fpu.c,v 1.2 2020/07/10 16:10:54 kettenis Exp $ */
+/* $OpenBSD: fpu.c,v 1.3 2021/01/09 13:14:02 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -22,6 +22,7 @@
#include <sys/user.h>
#include <machine/cpufunc.h>
+#include <machine/fenv.h>
void
save_vsx(struct proc *p)
@@ -68,7 +69,7 @@ restore_vsx(struct proc *p)
struct pcb *pcb = &p->p_addr->u_pcb;
struct fpreg *fp = &pcb->pcb_fpstate;
- if ((pcb->pcb_flags & (PCB_FP|PCB_VEC|PCB_VSX)) == 0)
+ if ((pcb->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX)) == 0)
memset(fp, 0, sizeof(*fp));
mtmsr(mfmsr() | (PSL_FP|PSL_VEC|PSL_VSX));
@@ -104,3 +105,28 @@ restore_vsx(struct proc *p)
mtmsr(mfmsr() & ~(PSL_FP|PSL_VEC|PSL_VSX));
}
+
+int
+fpu_sigcode(struct proc *p)
+{
+ struct trapframe *tf = p->p_md.md_regs;
+ struct fpreg *fp = &p->p_addr->u_pcb.pcb_fpstate;
+ int code = FPE_FLTINV;
+
+ KASSERT(tf->srr1 & PSL_FP);
+ tf->srr1 &= ~(PSL_FPU|PSL_VEC|PSL_VSX);
+ save_vsx(p);
+
+ if (fp->fp_fpscr & FE_INVALID)
+ code = FPE_FLTINV;
+ else if (fp->fp_fpscr & FE_DIVBYZERO)
+ code = FPE_FLTDIV;
+ else if (fp->fp_fpscr & FE_OVERFLOW)
+ code = FPE_FLTOVF;
+ else if (fp->fp_fpscr & FE_UNDERFLOW)
+ code = FPE_FLTUND;
+ else if (fp->fp_fpscr & FE_INEXACT)
+ code = FPE_FLTRES;
+
+ return code;
+}
diff --git a/sys/arch/powerpc64/powerpc64/machdep.c b/sys/arch/powerpc64/powerpc64/machdep.c
index 0ffbd3aee5c..cb1b89db3c8 100644
--- a/sys/arch/powerpc64/powerpc64/machdep.c
+++ b/sys/arch/powerpc64/powerpc64/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.66 2020/12/30 06:06:30 gkoehler Exp $ */
+/* $OpenBSD: machdep.c,v 1.67 2021/01/09 13:14:02 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -915,9 +915,9 @@ sendsig(sig_t catcher, int sig, sigset_t mask, const siginfo_t *ksip)
fp = (struct sigframe *)(STACKALIGN(fp - 1) - 288);
/* Save FPU state to PCB if necessary. */
- if (pcb->pcb_flags & (PCB_FP|PCB_VEC|PCB_VSX) &&
- tf->srr1 & (PSL_FP|PSL_VEC|PSL_VSX)) {
- tf->srr1 &= ~(PSL_FP|PSL_VEC|PSL_VSX);
+ if (pcb->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX) &&
+ tf->srr1 & (PSL_FPU|PSL_VEC|PSL_VSX)) {
+ tf->srr1 &= ~(PSL_FPU|PSL_VEC|PSL_VSX);
save_vsx(p);
}
@@ -937,7 +937,7 @@ sendsig(sig_t catcher, int sig, sigset_t mask, const siginfo_t *ksip)
frame.sf_sc.sc_vrsave = tf->vrsave;
/* Copy the saved FPU state into the frame if necessary. */
- if (pcb->pcb_flags & (PCB_FP|PCB_VEC|PCB_VSX)) {
+ if (pcb->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX)) {
memcpy(frame.sf_sc.sc_vsx, pcb->pcb_fpstate.fp_vsx,
sizeof(pcb->pcb_fpstate.fp_vsx));
frame.sf_sc.sc_fpscr = pcb->pcb_fpstate.fp_fpscr;
@@ -1016,7 +1016,7 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval)
tf->vrsave = ksc.sc_vrsave;
/* Write saved FPU state back to PCB if necessary. */
- if (pcb->pcb_flags & (PCB_FP|PCB_VEC|PCB_VSX)) {
+ if (pcb->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX)) {
memcpy(pcb->pcb_fpstate.fp_vsx, ksc.sc_vsx,
sizeof(pcb->pcb_fpstate.fp_vsx));
pcb->pcb_fpstate.fp_fpscr = ksc.sc_fpscr;
@@ -1049,9 +1049,9 @@ cpu_switchto(struct proc *old, struct proc *new)
struct pcb *pcb = &old->p_addr->u_pcb;
struct trapframe *tf = old->p_md.md_regs;
- if (pcb->pcb_flags & (PCB_FP|PCB_VEC|PCB_VSX) &&
- tf->srr1 & (PSL_FP|PSL_VEC|PSL_VSX)) {
- tf->srr1 &= ~(PSL_FP|PSL_VEC|PSL_VSX);
+ if (pcb->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX) &&
+ tf->srr1 & (PSL_FPU|PSL_VEC|PSL_VSX)) {
+ tf->srr1 &= ~(PSL_FPU|PSL_VEC|PSL_VSX);
save_vsx(old);
}
diff --git a/sys/arch/powerpc64/powerpc64/process_machdep.c b/sys/arch/powerpc64/powerpc64/process_machdep.c
index 5d7fcecf013..9525d6da4a3 100644
--- a/sys/arch/powerpc64/powerpc64/process_machdep.c
+++ b/sys/arch/powerpc64/powerpc64/process_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: process_machdep.c,v 1.4 2020/07/14 09:41:30 kettenis Exp $ */
+/* $OpenBSD: process_machdep.c,v 1.5 2021/01/09 13:14:02 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -50,12 +50,12 @@ process_read_fpregs(struct proc *p, struct fpreg *regs)
struct trapframe *tf = p->p_md.md_regs;
struct pcb *pcb = &p->p_addr->u_pcb;
- if (tf->srr1 & (PSL_FP|PSL_VEC|PSL_VSX)) {
- tf->srr1 &= ~(PSL_FP|PSL_VEC|PSL_VSX);
+ if (tf->srr1 & (PSL_FPU|PSL_VEC|PSL_VSX)) {
+ tf->srr1 &= ~(PSL_FPU|PSL_VEC|PSL_VSX);
save_vsx(p);
}
- if (pcb->pcb_flags & (PCB_FP|PCB_VEC|PCB_VSX))
+ if (pcb->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX))
memcpy(regs, &pcb->pcb_fpstate, sizeof(*regs));
else
memset(regs, 0, sizeof(*regs));
@@ -98,8 +98,8 @@ process_write_regs(struct proc *p, struct reg *regs)
{
struct trapframe *tf = p->p_md.md_regs;
- regs->r_ps &= ~(PSL_FP|PSL_VEC|PSL_VSX);
- regs->r_ps |= (tf->srr1 & (PSL_FP|PSL_VEC|PSL_VSX));
+ regs->r_ps &= ~(PSL_FPU|PSL_VEC|PSL_VSX);
+ regs->r_ps |= (tf->srr1 & (PSL_FPU|PSL_VEC|PSL_VSX));
if (regs->r_ps != tf->srr1)
return EINVAL;
@@ -122,11 +122,9 @@ process_write_fpregs(struct proc *p, struct fpreg *regs)
struct trapframe *tf = p->p_md.md_regs;
struct pcb *pcb = &p->p_addr->u_pcb;
- if (tf->srr1 & (PSL_FP|PSL_VEC|PSL_VSX))
- tf->srr1 &= ~(PSL_FP|PSL_VEC|PSL_VSX);
-
+ tf->srr1 &= ~(PSL_FPU|PSL_VEC|PSL_VSX);
memcpy(&pcb->pcb_fpstate, regs, sizeof(*regs));
- pcb->pcb_flags |= (PCB_FP|PCB_VEC|PCB_VSX);
+ pcb->pcb_flags |= (PCB_FPU|PCB_VEC|PCB_VSX);
tf->vrsave = regs->fp_vrsave;
diff --git a/sys/arch/powerpc64/powerpc64/trap.c b/sys/arch/powerpc64/powerpc64/trap.c
index d8a89f6fa35..11eee18c707 100644
--- a/sys/arch/powerpc64/powerpc64/trap.c
+++ b/sys/arch/powerpc64/powerpc64/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.48 2020/12/23 10:47:10 kettenis Exp $ */
+/* $OpenBSD: trap.c,v 1.49 2021/01/09 13:14:02 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -59,7 +59,7 @@ trap(struct trapframe *frame)
int error, sig, code;
/* Disable access to floating-point and vector registers. */
- mtmsr(mfmsr() & ~(PSL_FP|PSL_VEC|PSL_VSX));
+ mtmsr(mfmsr() & ~(PSL_FPU|PSL_VEC|PSL_VSX));
switch (type) {
case EXC_DECR:
@@ -108,7 +108,7 @@ trap(struct trapframe *frame)
db_ktrap(T_BREAKPOINT, frame);
return;
}
- break;
+ goto fatal;
case EXC_TRC:
db_ktrap(T_BREAKPOINT, frame); /* single-stepping */
return;
@@ -333,7 +333,7 @@ trap(struct trapframe *frame)
case EXC_PGM|EXC_USER:
sv.sival_ptr = (void *)frame->srr0;
if (frame->srr1 & EXC_PGM_FPENABLED)
- trapsignal(p, SIGFPE, 0, FPE_FLTINV, sv);
+ trapsignal(p, SIGFPE, 0, fpu_sigcode(p), sv);
else if (frame->srr1 & EXC_PGM_TRAP)
trapsignal(p, SIGTRAP, 0, TRAP_BRKPT, sv);
else
@@ -343,8 +343,8 @@ trap(struct trapframe *frame)
case EXC_FPU|EXC_USER:
if ((frame->srr1 & (PSL_FP|PSL_VEC|PSL_VSX)) == 0)
restore_vsx(p);
- curpcb->pcb_flags |= PCB_FP;
- frame->srr1 |= PSL_FP;
+ curpcb->pcb_flags |= PCB_FPU;
+ frame->srr1 |= PSL_FPU;
break;
case EXC_TRC|EXC_USER:
diff --git a/sys/arch/powerpc64/powerpc64/vm_machdep.c b/sys/arch/powerpc64/powerpc64/vm_machdep.c
index e3960e72f67..51e6daaf2d0 100644
--- a/sys/arch/powerpc64/powerpc64/vm_machdep.c
+++ b/sys/arch/powerpc64/powerpc64/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.6 2021/01/07 19:02:45 kettenis Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.7 2021/01/09 13:14:02 kettenis Exp $ */
/*-
* Copyright (c) 1995 Charles M. Hannum. All rights reserved.
@@ -55,6 +55,7 @@
#include <uvm/uvm_extern.h>
#include <machine/cpu.h>
+#include <machine/fpu.h>
#include <machine/reg.h>
/*
@@ -68,11 +69,19 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
void (*func)(void *), void *arg)
{
struct pcb *pcb = &p2->p_addr->u_pcb;
+ struct pcb *pcb1 = &p1->p_addr->u_pcb;
struct trapframe *tf;
struct callframe *cf;
struct switchframe *sf;
register_t kstack;
+ /* Save FPU state to PCB if necessary. */
+ if (pcb1->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX) &&
+ p1->p_md.md_regs->srr1 & (PSL_FPU|PSL_VEC|PSL_VSX)) {
+ p1->p_md.md_regs->srr1 &= ~(PSL_FPU|PSL_VEC|PSL_VSX);
+ save_vsx(p1);
+ }
+
/* Copy the pcb. */
*pcb = p1->p_addr->u_pcb;