Home | History | Annotate | Line # | Download | only in riscv
      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
     60 fpu_disable(void)
     61 {
     62 	csr_sstatus_clear(SR_FS);
     63 }
     64 
     65 static 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
     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
    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
    203 fpu_state_release(lwp_t *l)
    204 {
    205 	l->l_md.md_utf->tf_sr &= ~SR_FS;
    206 	fpu_disable();
    207 }
    208