summaryrefslogtreecommitdiff
path: root/sys/arch/powerpc64
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2021-01-09 13:14:03 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2021-01-09 13:14:03 +0000
commit0ea7c6d1bf47beeebe5b0145bf7538c1cd497472 (patch)
tree9a7af0230c3ebe33dd04a2cbf5e0a7e4bda45bda /sys/arch/powerpc64
parent300bd3b7402f833f4606edaa82c1784a7d21b7e9 (diff)
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@
Diffstat (limited to 'sys/arch/powerpc64')
-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;