fpu.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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. #include <sys/cdefs.h>
  36. __FBSDID("$FreeBSD$");
  37. #include <sys/param.h>
  38. #include <sys/proc.h>
  39. #include <sys/systm.h>
  40. #include <sys/limits.h>
  41. #include <machine/fpu.h>
  42. #include <machine/pcb.h>
  43. #include <machine/psl.h>
  44. static void
  45. save_fpu_int(struct thread *td)
  46. {
  47. register_t msr;
  48. struct pcb *pcb;
  49. pcb = td->td_pcb;
  50. /*
  51. * Temporarily re-enable floating-point during the save
  52. */
  53. msr = mfmsr();
  54. if (pcb->pcb_flags & PCB_VSX)
  55. mtmsr(msr | PSL_FP | PSL_VSX);
  56. else
  57. mtmsr(msr | PSL_FP);
  58. /*
  59. * Save the floating-point registers and FPSCR to the PCB
  60. */
  61. if (pcb->pcb_flags & PCB_VSX) {
  62. #define SFP(n) __asm ("stxvw4x " #n ", 0,%0" \
  63. :: "b"(&pcb->pcb_fpu.fpr[n]));
  64. SFP(0); SFP(1); SFP(2); SFP(3);
  65. SFP(4); SFP(5); SFP(6); SFP(7);
  66. SFP(8); SFP(9); SFP(10); SFP(11);
  67. SFP(12); SFP(13); SFP(14); SFP(15);
  68. SFP(16); SFP(17); SFP(18); SFP(19);
  69. SFP(20); SFP(21); SFP(22); SFP(23);
  70. SFP(24); SFP(25); SFP(26); SFP(27);
  71. SFP(28); SFP(29); SFP(30); SFP(31);
  72. #undef SFP
  73. } else {
  74. #define SFP(n) __asm ("stfd " #n ", 0(%0)" \
  75. :: "b"(&pcb->pcb_fpu.fpr[n].fpr));
  76. SFP(0); SFP(1); SFP(2); SFP(3);
  77. SFP(4); SFP(5); SFP(6); SFP(7);
  78. SFP(8); SFP(9); SFP(10); SFP(11);
  79. SFP(12); SFP(13); SFP(14); SFP(15);
  80. SFP(16); SFP(17); SFP(18); SFP(19);
  81. SFP(20); SFP(21); SFP(22); SFP(23);
  82. SFP(24); SFP(25); SFP(26); SFP(27);
  83. SFP(28); SFP(29); SFP(30); SFP(31);
  84. #undef SFP
  85. }
  86. __asm __volatile ("mffs 0; stfd 0,0(%0)" :: "b"(&pcb->pcb_fpu.fpscr));
  87. /*
  88. * Disable floating-point again
  89. */
  90. isync();
  91. mtmsr(msr);
  92. }
  93. void
  94. enable_fpu(struct thread *td)
  95. {
  96. register_t msr;
  97. struct pcb *pcb;
  98. struct trapframe *tf;
  99. pcb = td->td_pcb;
  100. tf = trapframe(td);
  101. /*
  102. * Save the thread's FPU CPU number, and set the CPU's current
  103. * FPU thread
  104. */
  105. td->td_pcb->pcb_fpcpu = PCPU_GET(cpuid);
  106. PCPU_SET(fputhread, td);
  107. /*
  108. * Enable the FPU for when the thread returns from the exception.
  109. * If this is the first time the FPU has been used by the thread,
  110. * initialise the FPU registers and FPSCR to 0, and set the flag
  111. * to indicate that the FPU is in use.
  112. */
  113. pcb->pcb_flags |= PCB_FPU;
  114. if (pcb->pcb_flags & PCB_VSX)
  115. tf->srr1 |= PSL_FP | PSL_VSX;
  116. else
  117. tf->srr1 |= PSL_FP;
  118. if (!(pcb->pcb_flags & PCB_FPREGS)) {
  119. memset(&pcb->pcb_fpu, 0, sizeof pcb->pcb_fpu);
  120. pcb->pcb_flags |= PCB_FPREGS;
  121. }
  122. /*
  123. * Temporarily enable floating-point so the registers
  124. * can be restored.
  125. */
  126. msr = mfmsr();
  127. if (pcb->pcb_flags & PCB_VSX)
  128. mtmsr(msr | PSL_FP | PSL_VSX);
  129. else
  130. mtmsr(msr | PSL_FP);
  131. /*
  132. * Load the floating point registers and FPSCR from the PCB.
  133. * (A value of 0xff for mtfsf specifies that all 8 4-bit fields
  134. * of the saved FPSCR are to be loaded from the FPU reg).
  135. */
  136. __asm __volatile ("lfd 0,0(%0); mtfsf 0xff,0"
  137. :: "b"(&pcb->pcb_fpu.fpscr));
  138. if (pcb->pcb_flags & PCB_VSX) {
  139. #define LFP(n) __asm ("lxvw4x " #n ", 0,%0" \
  140. :: "b"(&pcb->pcb_fpu.fpr[n]));
  141. LFP(0); LFP(1); LFP(2); LFP(3);
  142. LFP(4); LFP(5); LFP(6); LFP(7);
  143. LFP(8); LFP(9); LFP(10); LFP(11);
  144. LFP(12); LFP(13); LFP(14); LFP(15);
  145. LFP(16); LFP(17); LFP(18); LFP(19);
  146. LFP(20); LFP(21); LFP(22); LFP(23);
  147. LFP(24); LFP(25); LFP(26); LFP(27);
  148. LFP(28); LFP(29); LFP(30); LFP(31);
  149. #undef LFP
  150. } else {
  151. #define LFP(n) __asm ("lfd " #n ", 0(%0)" \
  152. :: "b"(&pcb->pcb_fpu.fpr[n].fpr));
  153. LFP(0); LFP(1); LFP(2); LFP(3);
  154. LFP(4); LFP(5); LFP(6); LFP(7);
  155. LFP(8); LFP(9); LFP(10); LFP(11);
  156. LFP(12); LFP(13); LFP(14); LFP(15);
  157. LFP(16); LFP(17); LFP(18); LFP(19);
  158. LFP(20); LFP(21); LFP(22); LFP(23);
  159. LFP(24); LFP(25); LFP(26); LFP(27);
  160. LFP(28); LFP(29); LFP(30); LFP(31);
  161. #undef LFP
  162. }
  163. isync();
  164. mtmsr(msr);
  165. }
  166. void
  167. save_fpu(struct thread *td)
  168. {
  169. struct pcb *pcb;
  170. pcb = td->td_pcb;
  171. save_fpu_int(td);
  172. /*
  173. * Clear the current fp thread and pcb's CPU id
  174. * XXX should this be left clear to allow lazy save/restore ?
  175. */
  176. pcb->pcb_fpcpu = INT_MAX;
  177. PCPU_SET(fputhread, NULL);
  178. }
  179. /*
  180. * Save fpu state without dropping ownership. This will only save state if
  181. * the current fpu thread is `td'.
  182. */
  183. void
  184. save_fpu_nodrop(struct thread *td)
  185. {
  186. if (td == PCPU_GET(fputhread))
  187. save_fpu_int(td);
  188. }
  189. /*
  190. * Clear Floating-Point Status and Control Register
  191. */
  192. void
  193. cleanup_fpscr()
  194. {
  195. register_t msr;
  196. msr = mfmsr();
  197. mtmsr(msr | PSL_FP);
  198. mtfsf(0);
  199. isync();
  200. mtmsr(msr);
  201. }
  202. /*
  203. * Get the current fp exception
  204. */
  205. u_int
  206. get_fpu_exception(struct thread *td)
  207. {
  208. register_t msr;
  209. u_int ucode;
  210. register_t reg;
  211. critical_enter();
  212. msr = mfmsr();
  213. mtmsr(msr | PSL_FP);
  214. reg = mffs();
  215. isync();
  216. mtmsr(msr);
  217. critical_exit();
  218. if (reg & FPSCR_ZX)
  219. ucode = FPE_FLTDIV;
  220. else if (reg & FPSCR_OX)
  221. ucode = FPE_FLTOVF;
  222. else if (reg & FPSCR_UX)
  223. ucode = FPE_FLTUND;
  224. else if (reg & FPSCR_XX)
  225. ucode = FPE_FLTRES;
  226. else
  227. ucode = FPE_FLTINV;
  228. return ucode;
  229. }