1/*- 2 * Copyright (C) 1996 Wolfgang Solfrank. 3 * Copyright (C) 1996 TooLs GmbH. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by TooLs GmbH. 17 * 4. The name of TooLs GmbH may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $NetBSD: fpu.c,v 1.5 2001/07/22 11:29:46 wiz Exp $ 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD$"); 36 37#include <sys/param.h> 38#include <sys/proc.h> 39#include <sys/systm.h> 40#include <sys/limits.h> 41 42#include <machine/fpu.h> 43#include <machine/pcb.h> 44#include <machine/psl.h> 45 46void 47enable_fpu(struct thread *td) 48{ 49 int msr; 50 struct pcb *pcb; 51 struct trapframe *tf; 52 53 pcb = td->td_pcb; 54 tf = trapframe(td); 55 56 /* 57 * Save the thread's FPU CPU number, and set the CPU's current 58 * FPU thread 59 */ 60 td->td_pcb->pcb_fpcpu = PCPU_GET(cpuid); 61 PCPU_SET(fputhread, td); 62 63 /* 64 * Enable the FPU for when the thread returns from the exception. 65 * If this is the first time the FPU has been used by the thread, 66 * initialise the FPU registers and FPSCR to 0, and set the flag 67 * to indicate that the FPU is in use. 68 */ 69 pcb->pcb_flags |= PCB_FPU; 70 if (pcb->pcb_flags & PCB_VSX) 71 tf->srr1 |= PSL_FP | PSL_VSX; 72 else 73 tf->srr1 |= PSL_FP; 74 if (!(pcb->pcb_flags & PCB_FPREGS)) { 75 memset(&pcb->pcb_fpu, 0, sizeof pcb->pcb_fpu); 76 pcb->pcb_flags |= PCB_FPREGS; 77 } 78 79 /* 80 * Temporarily enable floating-point so the registers 81 * can be restored. 82 */ 83 msr = mfmsr(); 84 if (pcb->pcb_flags & PCB_VSX) 85 mtmsr(msr | PSL_FP | PSL_VSX); 86 else 87 mtmsr(msr | PSL_FP); 88 isync(); 89 90 /* 91 * Load the floating point registers and FPSCR from the PCB. 92 * (A value of 0xff for mtfsf specifies that all 8 4-bit fields 93 * of the saved FPSCR are to be loaded from the FPU reg). 94 */ 95 __asm __volatile ("lfd 0,0(%0); mtfsf 0xff,0" 96 :: "b"(&pcb->pcb_fpu.fpscr)); 97 98 if (pcb->pcb_flags & PCB_VSX) { 99 #define LFP(n) __asm ("lxvw4x " #n ", 0,%0" \ 100 :: "b"(&pcb->pcb_fpu.fpr[n])); 101 LFP(0); LFP(1); LFP(2); LFP(3); 102 LFP(4); LFP(5); LFP(6); LFP(7); 103 LFP(8); LFP(9); LFP(10); LFP(11); 104 LFP(12); LFP(13); LFP(14); LFP(15); 105 LFP(16); LFP(17); LFP(18); LFP(19); 106 LFP(20); LFP(21); LFP(22); LFP(23); 107 LFP(24); LFP(25); LFP(26); LFP(27); 108 LFP(28); LFP(29); LFP(30); LFP(31); 109 #undef LFP 110 } else { 111 #define LFP(n) __asm ("lfd " #n ", 0(%0)" \ 112 :: "b"(&pcb->pcb_fpu.fpr[n])); 113 LFP(0); LFP(1); LFP(2); LFP(3); 114 LFP(4); LFP(5); LFP(6); LFP(7); 115 LFP(8); LFP(9); LFP(10); LFP(11); 116 LFP(12); LFP(13); LFP(14); LFP(15); 117 LFP(16); LFP(17); LFP(18); LFP(19); 118 LFP(20); LFP(21); LFP(22); LFP(23); 119 LFP(24); LFP(25); LFP(26); LFP(27); 120 LFP(28); LFP(29); LFP(30); LFP(31); 121 #undef LFP 122 } 123 124 isync(); 125 mtmsr(msr); 126} 127 128void 129save_fpu(struct thread *td) 130{ 131 int msr; 132 struct pcb *pcb; 133 134 pcb = td->td_pcb; 135 136 /* 137 * Temporarily re-enable floating-point during the save 138 */ 139 msr = mfmsr(); 140 if (pcb->pcb_flags & PCB_VSX) 141 mtmsr(msr | PSL_FP | PSL_VSX); 142 else 143 mtmsr(msr | PSL_FP); 144 isync(); 145 146 /* 147 * Save the floating-point registers and FPSCR to the PCB 148 */ 149 if (pcb->pcb_flags & PCB_VSX) { 150 #define SFP(n) __asm ("stxvw4x " #n ", 0,%0" \ 151 :: "b"(&pcb->pcb_fpu.fpr[n])); 152 SFP(0); SFP(1); SFP(2); SFP(3); 153 SFP(4); SFP(5); SFP(6); SFP(7); 154 SFP(8); SFP(9); SFP(10); SFP(11); 155 SFP(12); SFP(13); SFP(14); SFP(15); 156 SFP(16); SFP(17); SFP(18); SFP(19); 157 SFP(20); SFP(21); SFP(22); SFP(23); 158 SFP(24); SFP(25); SFP(26); SFP(27); 159 SFP(28); SFP(29); SFP(30); SFP(31); 160 #undef SFP 161 } else { 162 #define SFP(n) __asm ("stfd " #n ", 0(%0)" \ 163 :: "b"(&pcb->pcb_fpu.fpr[n])); 164 SFP(0); SFP(1); SFP(2); SFP(3); 165 SFP(4); SFP(5); SFP(6); SFP(7); 166 SFP(8); SFP(9); SFP(10); SFP(11); 167 SFP(12); SFP(13); SFP(14); SFP(15); 168 SFP(16); SFP(17); SFP(18); SFP(19); 169 SFP(20); SFP(21); SFP(22); SFP(23); 170 SFP(24); SFP(25); SFP(26); SFP(27); 171 SFP(28); SFP(29); SFP(30); SFP(31); 172 #undef SFP 173 } 174 __asm __volatile ("mffs 0; stfd 0,0(%0)" :: "b"(&pcb->pcb_fpu.fpscr)); 175 176 /* 177 * Disable floating-point again 178 */ 179 isync(); 180 mtmsr(msr); 181 182 /* 183 * Clear the current fp thread and pcb's CPU id 184 * XXX should this be left clear to allow lazy save/restore ? 185 */ 186 pcb->pcb_fpcpu = INT_MAX; 187 PCPU_SET(fputhread, NULL); 188} 189 190