xref: /openbsd/sys/arch/powerpc64/powerpc64/fpu.c (revision 1a1a23bd)
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