1 /* $NetBSD: fpu.c,v 1.7 2002/07/28 07:07:45 chs Exp $ */ 2 3 /* 4 * Copyright (C) 1996 Wolfgang Solfrank. 5 * Copyright (C) 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "opt_multiprocessor.h" 35 36 #include <sys/param.h> 37 #include <sys/proc.h> 38 #include <sys/systm.h> 39 #include <sys/user.h> 40 41 #include <machine/fpu.h> 42 #include <machine/psl.h> 43 44 void 45 enable_fpu(void) 46 { 47 struct cpu_info *ci = curcpu(); 48 struct proc *p = curproc; 49 struct pcb *pcb = &p->p_addr->u_pcb; 50 struct trapframe *tf = trapframe(p); 51 int msr; 52 53 KASSERT(pcb->pcb_fpcpu == NULL); 54 if (!(pcb->pcb_flags & PCB_FPU)) { 55 memset(&pcb->pcb_fpu, 0, sizeof pcb->pcb_fpu); 56 pcb->pcb_flags |= PCB_FPU; 57 } 58 msr = mfmsr(); 59 mtmsr((msr & ~PSL_EE) | PSL_FP); 60 asm volatile ("isync"); 61 if (ci->ci_fpuproc) { 62 save_fpu_cpu(); 63 } 64 KASSERT(ci->ci_fpuproc == NULL); 65 asm volatile ("lfd 0,0(%0); mtfsf 0xff,0" :: "b"(&pcb->pcb_fpu.fpscr)); 66 asm ("lfd 0,0(%0);" 67 "lfd 1,8(%0);" 68 "lfd 2,16(%0);" 69 "lfd 3,24(%0);" 70 "lfd 4,32(%0);" 71 "lfd 5,40(%0);" 72 "lfd 6,48(%0);" 73 "lfd 7,56(%0);" 74 "lfd 8,64(%0);" 75 "lfd 9,72(%0);" 76 "lfd 10,80(%0);" 77 "lfd 11,88(%0);" 78 "lfd 12,96(%0);" 79 "lfd 13,104(%0);" 80 "lfd 14,112(%0);" 81 "lfd 15,120(%0);" 82 "lfd 16,128(%0);" 83 "lfd 17,136(%0);" 84 "lfd 18,144(%0);" 85 "lfd 19,152(%0);" 86 "lfd 20,160(%0);" 87 "lfd 21,168(%0);" 88 "lfd 22,176(%0);" 89 "lfd 23,184(%0);" 90 "lfd 24,192(%0);" 91 "lfd 25,200(%0);" 92 "lfd 26,208(%0);" 93 "lfd 27,216(%0);" 94 "lfd 28,224(%0);" 95 "lfd 29,232(%0);" 96 "lfd 30,240(%0);" 97 "lfd 31,248(%0)" :: "b"(&pcb->pcb_fpu.fpr[0])); 98 asm volatile ("isync"); 99 tf->srr1 |= PSL_FP; 100 ci->ci_fpuproc = p; 101 pcb->pcb_fpcpu = ci; 102 asm volatile ("sync"); 103 mtmsr(msr); 104 } 105 106 /* 107 * Save the contents of the current CPU's FPU to its PCB. 108 */ 109 void 110 save_fpu_cpu(void) 111 { 112 struct cpu_info *ci = curcpu(); 113 struct proc *p; 114 struct pcb *pcb; 115 int msr; 116 117 msr = mfmsr(); 118 mtmsr((msr & ~PSL_EE) | PSL_FP); 119 __asm __volatile ("isync"); 120 p = ci->ci_fpuproc; 121 if (p == NULL) { 122 goto out; 123 } 124 pcb = &p->p_addr->u_pcb; 125 asm ("stfd 0,0(%0);" 126 "stfd 1,8(%0);" 127 "stfd 2,16(%0);" 128 "stfd 3,24(%0);" 129 "stfd 4,32(%0);" 130 "stfd 5,40(%0);" 131 "stfd 6,48(%0);" 132 "stfd 7,56(%0);" 133 "stfd 8,64(%0);" 134 "stfd 9,72(%0);" 135 "stfd 10,80(%0);" 136 "stfd 11,88(%0);" 137 "stfd 12,96(%0);" 138 "stfd 13,104(%0);" 139 "stfd 14,112(%0);" 140 "stfd 15,120(%0);" 141 "stfd 16,128(%0);" 142 "stfd 17,136(%0);" 143 "stfd 18,144(%0);" 144 "stfd 19,152(%0);" 145 "stfd 20,160(%0);" 146 "stfd 21,168(%0);" 147 "stfd 22,176(%0);" 148 "stfd 23,184(%0);" 149 "stfd 24,192(%0);" 150 "stfd 25,200(%0);" 151 "stfd 26,208(%0);" 152 "stfd 27,216(%0);" 153 "stfd 28,224(%0);" 154 "stfd 29,232(%0);" 155 "stfd 30,240(%0);" 156 "stfd 31,248(%0)" :: "b"(&pcb->pcb_fpu.fpr[0])); 157 asm volatile ("mffs 0; stfd 0,0(%0)" :: "b"(&pcb->pcb_fpu.fpscr)); 158 asm volatile ("sync"); 159 pcb->pcb_fpcpu = NULL; 160 ci->ci_fpuproc = NULL; 161 ci->ci_ev_fpusw.ev_count++; 162 asm volatile ("sync"); 163 out: 164 mtmsr(msr); 165 } 166 167 /* 168 * Save a process's FPU state to its PCB. The state may be in any CPU. 169 * The process must either be curproc or traced by curproc (and stopped). 170 * (The point being that the process must not run on another CPU during 171 * this function). 172 */ 173 void 174 save_fpu_proc(p) 175 struct proc *p; 176 { 177 struct pcb *pcb = &p->p_addr->u_pcb; 178 struct cpu_info *ci = curcpu(); 179 180 /* 181 * If it's already in the PCB, there's nothing to do. 182 */ 183 184 if (pcb->pcb_fpcpu == NULL) { 185 return; 186 } 187 188 /* 189 * If the state is in the current CPU, just flush the current CPU's 190 * state. 191 */ 192 193 if (p == ci->ci_fpuproc) { 194 save_fpu_cpu(); 195 return; 196 } 197 198 #ifdef MULTIPROCESSOR 199 200 /* 201 * It must be on another CPU, flush it from there. 202 */ 203 204 mp_save_fpu_proc(p); 205 #endif 206 } 207