1 /* $OpenBSD: fpu.c,v 1.4 2021/04/14 18:35:14 kettenis Exp $ */
2
3 /*
4 * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/param.h>
20 #include <sys/proc.h>
21 #include <sys/systm.h>
22 #include <sys/user.h>
23
24 #include <machine/cpufunc.h>
25 #include <machine/fenv.h>
26
27 void
save_vsx(struct proc * p)28 save_vsx(struct proc *p)
29 {
30 struct fpreg *fp = &p->p_addr->u_pcb.pcb_fpstate;
31
32 mtmsr(mfmsr() | (PSL_FP|PSL_VEC|PSL_VSX));
33
34 isync();
35
36 #define STXVVSR(n) \
37 __asm volatile ("stxvd2x %%vs" #n ", 0, %0" :: "b"(&fp->fp_vsx[(n)]));
38
39 STXVVSR(0); STXVVSR(1); STXVVSR(2); STXVVSR(3);
40 STXVVSR(4); STXVVSR(5); STXVVSR(6); STXVVSR(7);
41 STXVVSR(8); STXVVSR(9); STXVVSR(10); STXVVSR(11);
42 STXVVSR(12); STXVVSR(13); STXVVSR(14); STXVVSR(15);
43 STXVVSR(16); STXVVSR(17); STXVVSR(18); STXVVSR(19);
44 STXVVSR(20); STXVVSR(21); STXVVSR(22); STXVVSR(23);
45 STXVVSR(24); STXVVSR(25); STXVVSR(26); STXVVSR(27);
46 STXVVSR(28); STXVVSR(29); STXVVSR(30); STXVVSR(31);
47 STXVVSR(32); STXVVSR(33); STXVVSR(34); STXVVSR(35);
48 STXVVSR(36); STXVVSR(37); STXVVSR(38); STXVVSR(39);
49 STXVVSR(40); STXVVSR(41); STXVVSR(42); STXVVSR(43);
50 STXVVSR(44); STXVVSR(45); STXVVSR(46); STXVVSR(47);
51 STXVVSR(48); STXVVSR(49); STXVVSR(50); STXVVSR(51);
52 STXVVSR(52); STXVVSR(53); STXVVSR(54); STXVVSR(55);
53 STXVVSR(56); STXVVSR(57); STXVVSR(58); STXVVSR(59);
54 STXVVSR(60); STXVVSR(61); STXVVSR(62); STXVVSR(63);
55
56 __asm volatile ("mffs %%f0; stfd %%f0, 0(%0)"
57 :: "b"(&fp->fp_fpscr));
58 __asm volatile ("mfvscr %%v0; stvewx %%v0, 0, %0"
59 :: "b"(&fp->fp_vscr));
60
61 isync();
62
63 mtmsr(mfmsr() & ~(PSL_FP|PSL_VEC|PSL_VSX));
64 }
65
66 void
restore_vsx(struct proc * p)67 restore_vsx(struct proc *p)
68 {
69 struct pcb *pcb = &p->p_addr->u_pcb;
70 struct fpreg *fp = &pcb->pcb_fpstate;
71
72 if ((pcb->pcb_flags & (PCB_FPU|PCB_VEC|PCB_VSX)) == 0)
73 memset(fp, 0, sizeof(*fp));
74
75 mtmsr(mfmsr() | (PSL_FP|PSL_VEC|PSL_VSX));
76
77 isync();
78
79 __asm volatile ("lfd %%f0, 0(%0); mtfsf 0xff,%%f0"
80 :: "b"(&fp->fp_fpscr));
81 __asm volatile ("vxor %%v0, %%v0, %%v0; lvewx %%v0, 0, %0; mtvscr %%v0"
82 :: "b"(&fp->fp_vscr));
83
84 #define LXVVSR(n) \
85 __asm volatile ("lxvd2x %%vs" #n ", 0, %0" :: "b"(&fp->fp_vsx[(n)]));
86
87 LXVVSR(0); LXVVSR(1); LXVVSR(2); LXVVSR(3);
88 LXVVSR(4); LXVVSR(5); LXVVSR(6); LXVVSR(7);
89 LXVVSR(8); LXVVSR(9); LXVVSR(10); LXVVSR(11);
90 LXVVSR(12); LXVVSR(13); LXVVSR(14); LXVVSR(15);
91 LXVVSR(16); LXVVSR(17); LXVVSR(18); LXVVSR(19);
92 LXVVSR(20); LXVVSR(21); LXVVSR(22); LXVVSR(23);
93 LXVVSR(24); LXVVSR(25); LXVVSR(26); LXVVSR(27);
94 LXVVSR(28); LXVVSR(29); LXVVSR(30); LXVVSR(31);
95 LXVVSR(32); LXVVSR(33); LXVVSR(34); LXVVSR(35);
96 LXVVSR(36); LXVVSR(37); LXVVSR(38); LXVVSR(39);
97 LXVVSR(40); LXVVSR(41); LXVVSR(42); LXVVSR(43);
98 LXVVSR(44); LXVVSR(45); LXVVSR(46); LXVVSR(47);
99 LXVVSR(48); LXVVSR(49); LXVVSR(50); LXVVSR(51);
100 LXVVSR(52); LXVVSR(53); LXVVSR(54); LXVVSR(55);
101 LXVVSR(56); LXVVSR(57); LXVVSR(58); LXVVSR(59);
102 LXVVSR(60); LXVVSR(61); LXVVSR(62); LXVVSR(63);
103
104 isync();
105
106 mtmsr(mfmsr() & ~(PSL_FP|PSL_VEC|PSL_VSX));
107 }
108
109 int
fpu_sigcode(struct proc * p)110 fpu_sigcode(struct proc *p)
111 {
112 struct trapframe *tf = p->p_md.md_regs;
113 struct fpreg *fp = &p->p_addr->u_pcb.pcb_fpstate;
114 int code = FPE_FLTINV;
115
116 KASSERT(tf->srr1 & PSL_FP);
117 tf->srr1 &= ~(PSL_FPU|PSL_VEC|PSL_VSX);
118 save_vsx(p);
119
120 if (fp->fp_fpscr & FE_INVALID)
121 code = FPE_FLTINV;
122 else if (fp->fp_fpscr & FE_DIVBYZERO)
123 code = FPE_FLTDIV;
124 else if (fp->fp_fpscr & FE_OVERFLOW)
125 code = FPE_FLTOVF;
126 else if (fp->fp_fpscr & FE_UNDERFLOW)
127 code = FPE_FLTUND;
128 else if (fp->fp_fpscr & FE_INEXACT)
129 code = FPE_FLTRES;
130
131 return code;
132 }
133