xref: /netbsd-src/sys/arch/riscv/riscv/fpu.c (revision 75b842b84762e0251223b719bf77fbef2e651bf6)
1 /*	$NetBSD: fpu.c,v 1.3 2023/05/07 12:41:49 skrll Exp $	*/
2 
3 /*-
4  * Copyright (c) 2014 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Matt Thomas of 3am Software Foundry.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.3 2023/05/07 12:41:49 skrll Exp $");
34 
35 #include "opt_multiprocessor.h"
36 
37 #include <sys/param.h>
38 #include <sys/mutex.h>
39 #include <sys/condvar.h>
40 #include <sys/cpu.h>
41 #include <sys/proc.h>
42 #include <sys/lwp.h>
43 #include <sys/pcu.h>
44 
45 #include <riscv/locore.h>
46 #include <riscv/frame.h>
47 
48 static void fpu_state_save(lwp_t *);
49 static void fpu_state_load(lwp_t *, u_int);
50 static void fpu_state_release(lwp_t *);
51 
52 const pcu_ops_t pcu_fpu_ops = {
53 	.pcu_id = PCU_FPU,
54 	.pcu_state_save = fpu_state_save,
55 	.pcu_state_load = fpu_state_load,
56 	.pcu_state_release = fpu_state_release
57 };
58 
59 static void
fpu_disable(void)60 fpu_disable(void)
61 {
62 	csr_sstatus_clear(SR_FS);
63 }
64 
65 static void
fpu_enable(void)66 fpu_enable(void)
67 {
68 	csr_sstatus_clear(SR_FS);
69 	csr_sstatus_set(__SHIFTIN(SR_FS_CLEAN, SR_FS));
70 }
71 
72 void
fpu_state_save(lwp_t * l)73 fpu_state_save(lwp_t *l)
74 {
75 //	struct trapframe * const tf = l->l_md.md_utf;
76 	struct pcb * const pcb = lwp_getpcb(l);
77 	struct fpreg * const fp = &pcb->pcb_fpregs;
78 
79 	KASSERT(l->l_pcu_cpu[PCU_FPU] == curcpu());
80 
81 	curcpu()->ci_ev_fpu_saves.ev_count++;
82 
83 	// Enable FPU to save FP state
84 	fpu_enable();
85 
86 	// Save FCSR
87 	fp->r_fcsr = fcsr_read();
88 
89 	// Save FP register values.
90 	__asm(	"fsd	f0, (0*%1)(%0)"
91 	"\n\t"	"fsd	f1, (1*%1)(%0)"
92 	"\n\t"	"fsd	f2, (2*%1)(%0)"
93 	"\n\t"	"fsd	f3, (3*%1)(%0)"
94 	"\n\t"	"fsd	f4, (4*%1)(%0)"
95 	"\n\t"	"fsd	f5, (5*%1)(%0)"
96 	"\n\t"	"fsd	f6, (6*%1)(%0)"
97 	"\n\t"	"fsd	f7, (7*%1)(%0)"
98 	"\n\t"	"fsd	f8, (8*%1)(%0)"
99 	"\n\t"	"fsd	f9, (9*%1)(%0)"
100 	"\n\t"	"fsd	f10, (10*%1)(%0)"
101 	"\n\t"	"fsd	f11, (11*%1)(%0)"
102 	"\n\t"	"fsd	f12, (12*%1)(%0)"
103 	"\n\t"	"fsd	f13, (13*%1)(%0)"
104 	"\n\t"	"fsd	f14, (14*%1)(%0)"
105 	"\n\t"	"fsd	f15, (15*%1)(%0)"
106 	"\n\t"	"fsd	f16, (16*%1)(%0)"
107 	"\n\t"	"fsd	f17, (17*%1)(%0)"
108 	"\n\t"	"fsd	f18, (18*%1)(%0)"
109 	"\n\t"	"fsd	f19, (19*%1)(%0)"
110 	"\n\t"	"fsd	f20, (20*%1)(%0)"
111 	"\n\t"	"fsd	f21, (21*%1)(%0)"
112 	"\n\t"	"fsd	f22, (22*%1)(%0)"
113 	"\n\t"	"fsd	f23, (23*%1)(%0)"
114 	"\n\t"	"fsd	f24, (24*%1)(%0)"
115 	"\n\t"	"fsd	f25, (25*%1)(%0)"
116 	"\n\t"	"fsd	f26, (26*%1)(%0)"
117 	"\n\t"	"fsd	f27, (27*%1)(%0)"
118 	"\n\t"	"fsd	f28, (28*%1)(%0)"
119 	"\n\t"	"fsd	f29, (29*%1)(%0)"
120 	"\n\t"	"fsd	f30, (30*%1)(%0)"
121 	"\n\t"	"fsd	f31, (31*%1)(%0)"
122 	   ::	"r"(fp->r_fpreg),
123 		"i"(sizeof(fp->r_fpreg[0])) : "memory");
124 
125 	// Disable the FPU
126 	fpu_disable();
127 }
128 
129 void
fpu_state_load(lwp_t * l,u_int flags)130 fpu_state_load(lwp_t *l, u_int flags)
131 {
132 	struct trapframe * const tf = l->l_md.md_utf;
133 	struct pcb * const pcb = lwp_getpcb(l);
134 	struct fpreg * const fp = &pcb->pcb_fpregs;
135 
136 	KASSERT(l == curlwp);
137 //	KASSERT(l->l_pcu_cpu[PCU_FPU] == curcpu());
138 
139 	// If this is the first time the state is being loaded, zero it first.
140 	if (__predict_false((flags & PCU_VALID) == 0)) {
141 		memset(fp, 0, sizeof(*fp));
142 	}
143 
144 	// Enable the FP when this lwp return to userspace.
145 	tf->tf_sr &= ~SR_FS;
146 	tf->tf_sr |= __SHIFTIN(SR_FS_CLEAN, SR_FS);
147 
148 	// If this is a simple reenable, set the FPU enable flag and return
149 	if (flags & PCU_REENABLE) {
150 		curcpu()->ci_ev_fpu_reenables.ev_count++;
151 		return;
152 	}
153 
154 	curcpu()->ci_ev_fpu_loads.ev_count++;
155 
156 
157 	// Enabling to load FP state.  Interrupts will remain on.
158 	fpu_enable();
159 
160 	// load FP registers and establish processes' FP context.
161 	__asm(	"fld	f0, (0*%1)(%0)"
162 	"\n\t"	"fld	f1, (1*%1)(%0)"
163 	"\n\t"	"fld	f2, (2*%1)(%0)"
164 	"\n\t"	"fld	f3, (3*%1)(%0)"
165 	"\n\t"	"fld	f4, (4*%1)(%0)"
166 	"\n\t"	"fld	f5, (5*%1)(%0)"
167 	"\n\t"	"fld	f6, (6*%1)(%0)"
168 	"\n\t"	"fld	f7, (7*%1)(%0)"
169 	"\n\t"	"fld	f8, (8*%1)(%0)"
170 	"\n\t"	"fld	f9, (9*%1)(%0)"
171 	"\n\t"	"fld	f10, (10*%1)(%0)"
172 	"\n\t"	"fld	f11, (11*%1)(%0)"
173 	"\n\t"	"fld	f12, (12*%1)(%0)"
174 	"\n\t"	"fld	f13, (13*%1)(%0)"
175 	"\n\t"	"fld	f14, (14*%1)(%0)"
176 	"\n\t"	"fld	f15, (15*%1)(%0)"
177 	"\n\t"	"fld	f16, (16*%1)(%0)"
178 	"\n\t"	"fld	f17, (17*%1)(%0)"
179 	"\n\t"	"fld	f18, (18*%1)(%0)"
180 	"\n\t"	"fld	f19, (19*%1)(%0)"
181 	"\n\t"	"fld	f20, (20*%1)(%0)"
182 	"\n\t"	"fld	f21, (21*%1)(%0)"
183 	"\n\t"	"fld	f22, (22*%1)(%0)"
184 	"\n\t"	"fld	f23, (23*%1)(%0)"
185 	"\n\t"	"fld	f24, (24*%1)(%0)"
186 	"\n\t"	"fld	f25, (25*%1)(%0)"
187 	"\n\t"	"fld	f26, (26*%1)(%0)"
188 	"\n\t"	"fld	f27, (27*%1)(%0)"
189 	"\n\t"	"fld	f28, (28*%1)(%0)"
190 	"\n\t"	"fld	f29, (29*%1)(%0)"
191 	"\n\t"	"fld	f30, (30*%1)(%0)"
192 	"\n\t"	"fld	f31, (31*%1)(%0)"
193 	   ::	"r"(fp->r_fpreg),
194 		"i"(sizeof(fp->r_fpreg[0])): "memory");
195 
196 	// load FPCSR and disable FPU again
197 	fcsr_write(fp->r_fcsr);
198 
199 	fpu_disable();
200 }
201 
202 void
fpu_state_release(lwp_t * l)203 fpu_state_release(lwp_t *l)
204 {
205 	l->l_md.md_utf->tf_sr &= ~SR_FS;
206 	fpu_disable();
207 }
208