1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 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 * $NetBSD: fpu.c,v 1.5 2001/07/22 11:29:46 wiz Exp $ 34 */ 35 36 #include <sys/param.h> 37 #include <sys/proc.h> 38 #include <sys/systm.h> 39 #include <sys/limits.h> 40 41 #include <machine/altivec.h> 42 #include <machine/pcb.h> 43 #include <machine/psl.h> 44 45 static void 46 save_vec_int(struct thread *td) 47 { 48 int msr; 49 struct pcb *pcb; 50 51 pcb = td->td_pcb; 52 53 /* 54 * Temporarily re-enable the vector unit during the save 55 */ 56 msr = mfmsr(); 57 mtmsr(msr | PSL_VEC); 58 59 /* 60 * Save the vector registers and VSCR to the PCB 61 */ 62 #define STVX(n) __asm ("stvx %1,0,%0" \ 63 :: "b"(pcb->pcb_vec.vr[n]), "n"(n)); 64 STVX(0); STVX(1); STVX(2); STVX(3); 65 STVX(4); STVX(5); STVX(6); STVX(7); 66 STVX(8); STVX(9); STVX(10); STVX(11); 67 STVX(12); STVX(13); STVX(14); STVX(15); 68 STVX(16); STVX(17); STVX(18); STVX(19); 69 STVX(20); STVX(21); STVX(22); STVX(23); 70 STVX(24); STVX(25); STVX(26); STVX(27); 71 STVX(28); STVX(29); STVX(30); STVX(31); 72 #undef STVX 73 74 __asm __volatile("mfvscr 0; stvewx 0,0,%0" :: "b"(&pcb->pcb_vec.vscr)); 75 76 /* 77 * Disable vector unit again 78 */ 79 isync(); 80 mtmsr(msr); 81 82 } 83 84 void 85 enable_vec(struct thread *td) 86 { 87 int msr; 88 struct pcb *pcb; 89 struct trapframe *tf; 90 91 pcb = td->td_pcb; 92 tf = trapframe(td); 93 94 /* 95 * Save the thread's Altivec CPU number, and set the CPU's current 96 * vector thread 97 */ 98 td->td_pcb->pcb_veccpu = PCPU_GET(cpuid); 99 PCPU_SET(vecthread, td); 100 101 /* 102 * Enable the vector unit for when the thread returns from the 103 * exception. If this is the first time the unit has been used by 104 * the thread, initialise the vector registers and VSCR to 0, and 105 * set the flag to indicate that the vector unit is in use. 106 */ 107 pcb->pcb_flags |= PCB_VEC; 108 tf->srr1 |= PSL_VEC; 109 if (!(pcb->pcb_flags & PCB_VECREGS)) { 110 memset(&pcb->pcb_vec, 0, sizeof pcb->pcb_vec); 111 pcb->pcb_flags |= PCB_VECREGS; 112 } 113 114 /* 115 * Temporarily enable the vector unit so the registers 116 * can be restored. 117 */ 118 msr = mfmsr(); 119 mtmsr(msr | PSL_VEC); 120 121 /* 122 * Restore VSCR by first loading it into a vector and then into VSCR. 123 * (this needs to done before loading the user's vector registers 124 * since we need to use a scratch vector register) 125 */ 126 __asm __volatile("vxor 0,0,0; lvewx 0,0,%0; mtvscr 0" \ 127 :: "b"(&pcb->pcb_vec.vscr)); 128 129 #define LVX(n) __asm ("lvx " #n ",0,%0" \ 130 :: "b"(&pcb->pcb_vec.vr[n])); 131 LVX(0); LVX(1); LVX(2); LVX(3); 132 LVX(4); LVX(5); LVX(6); LVX(7); 133 LVX(8); LVX(9); LVX(10); LVX(11); 134 LVX(12); LVX(13); LVX(14); LVX(15); 135 LVX(16); LVX(17); LVX(18); LVX(19); 136 LVX(20); LVX(21); LVX(22); LVX(23); 137 LVX(24); LVX(25); LVX(26); LVX(27); 138 LVX(28); LVX(29); LVX(30); LVX(31); 139 #undef LVX 140 141 isync(); 142 mtmsr(msr); 143 } 144 145 void 146 save_vec(struct thread *td) 147 { 148 struct pcb *pcb; 149 150 pcb = td->td_pcb; 151 152 save_vec_int(td); 153 154 /* 155 * Clear the current vec thread and pcb's CPU id 156 * XXX should this be left clear to allow lazy save/restore ? 157 */ 158 pcb->pcb_veccpu = INT_MAX; 159 PCPU_SET(vecthread, NULL); 160 } 161 162 /* 163 * Save altivec state without dropping ownership. This will only save state if 164 * the current vector-thread is `td'. 165 */ 166 void 167 save_vec_nodrop(struct thread *td) 168 { 169 170 if (td == PCPU_GET(vecthread)) 171 save_vec_int(td); 172 } 173 174 void 175 enable_vec_kern(void) 176 { 177 mtmsr(mfmsr() | PSL_VEC); 178 } 179 180 void 181 disable_vec(struct thread *td) 182 { 183 register_t msr; 184 struct pcb *pcb; 185 struct trapframe *tf; 186 187 pcb = td->td_pcb; 188 tf = trapframe(td); 189 190 /* Disable PSL_VEC in kernel (if enabled) */ 191 msr = mfmsr() & ~PSL_VEC; 192 isync(); 193 mtmsr(msr); 194 195 /* 196 * Disable PSL_VEC in userspace. It will be re-enabled when 197 * an Altivec instruction is executed. 198 */ 199 tf->srr1 &= ~PSL_VEC; 200 pcb->pcb_flags &= ~PCB_VEC; 201 } 202