|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
27: * All Rights Reserved
28: *
29: * Permission to use, copy, modify, and distribute this software and
30: * its documentation for any purpose and without fee is hereby granted,
31: * provided that the above copyright notice appears in all copies and
32: * that both the copyright notice and this permission notice appear in
33: * supporting documentation.
34: *
35: * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
36: * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
37: * FOR A PARTICULAR PURPOSE.
38: *
39: * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
40: * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
41: * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
42: * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
43: * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44: */
45: /*
46: * MKLINUX-1.0DR2
47: */
48:
49: #include <cpus.h>
50: #include <assym.h>
51: #include <debug.h>
52: #include <ppc/asm.h>
53: #include <ppc/proc_reg.h>
54: #include <mach/ppc/vm_param.h>
55:
56:
57: .text
58: /*
59: * void fpu_save(void)
60: *
61: * Called when there's an exception or when get_state is called
62: * for the FPU state. Puts a copy of the current thread's state
63: * into the PCB pointed to by fpu_pcb, and leaves the FPU enabled.
64: *
65: * video_scroll.s assumes that ARG0-5 won't be trampled on, and
66: * that fpu_save doesn't need a frame, otherwise it would need
67: * a frame itself. Why not oblige!
68: *
69: * NOTE: This routine is meant for kernel Floating Point
70: * use. It is called to flush the current context to the correct
71: * pcb and leaves with MSR_FP on so the kernel can use the FPU.
72: *
73: * IT IS THE CALLERS RESPONSIBILITY TO TURN THE FPU OFF AFTER USE!!!
74: *
75: * The function fpu_disable is used to accomplish this from C language
76: * programs or is can be done at the end of an assembly routine.
77: */
78:
79: ENTRY(fpu_save, TAG_NO_FRAME_USED)
80: /*
81: * Turn the FPU back on (should this be a separate routine?)
82: */
83: mfmsr r0
84: andi. r0, r0, MASK(MSR_FP)
85: bne .L_fpu_save_no_owner
86:
87: mfmsr r0
88: ori r0, r0, MASK(MSR_FP) /* bit is in low-order 16 */
89: mtmsr r0
90: isync
91:
92: mfsprg ARG7, 0 /* HACK - need to get around r2 problem */
93:
94: lwz ARG6, PP_FPU_PCB(ARG7)
95:
96: /*
97: * See if any thread owns the FPU. If not, we can skip the state save.
98: */
99: cmpwi CR0, ARG6, 0
100: beq- CR0, .L_fpu_save_no_owner
101:
102: /*
103: * Save the current FPU state into the PCB of the thread that owns it.
104: */
105: stfd f0, PCB_FS_F0(ARG6)
106: stfd f1, PCB_FS_F1(ARG6)
107: stfd f2, PCB_FS_F2(ARG6)
108: stfd f3, PCB_FS_F3(ARG6)
109: stfd f4, PCB_FS_F4(ARG6)
110: stfd f5, PCB_FS_F5(ARG6)
111: stfd f6, PCB_FS_F6(ARG6)
112: stfd f7, PCB_FS_F7(ARG6)
113: mffs f0 /* fpscr in f0 low 32 bits*/
114: stfd f8, PCB_FS_F8(ARG6)
115: stfd f9, PCB_FS_F9(ARG6)
116: stfd f10, PCB_FS_F10(ARG6)
117: stfd f11, PCB_FS_F11(ARG6)
118: stfd f12, PCB_FS_F12(ARG6)
119: stfd f13, PCB_FS_F13(ARG6)
120: stfd f14, PCB_FS_F14(ARG6)
121: stfd f15, PCB_FS_F15(ARG6)
122: stfd f0, PCB_FS_FPSCR(ARG6) /* Store junk 32 bits+fpscr */
123: stfd f16, PCB_FS_F16(ARG6)
124: stfd f17, PCB_FS_F17(ARG6)
125: stfd f18, PCB_FS_F18(ARG6)
126: stfd f19, PCB_FS_F19(ARG6)
127: stfd f20, PCB_FS_F20(ARG6)
128: stfd f21, PCB_FS_F21(ARG6)
129: stfd f22, PCB_FS_F22(ARG6)
130: stfd f23, PCB_FS_F23(ARG6)
131: stfd f24, PCB_FS_F24(ARG6)
132: stfd f25, PCB_FS_F25(ARG6)
133: stfd f26, PCB_FS_F26(ARG6)
134: stfd f27, PCB_FS_F27(ARG6)
135: stfd f28, PCB_FS_F28(ARG6)
136: stfd f29, PCB_FS_F29(ARG6)
137: stfd f30, PCB_FS_F30(ARG6)
138: stfd f31, PCB_FS_F31(ARG6)
139:
140: /* Mark the FPU as having no owner now */
141: li r0, 0
142: stw r0, PP_FPU_PCB(ARG7)
143:
144: /*
145: * Turn off the FPU for the old owner
146: */
147: lwz r0, SS_SRR1(ARG6)
148: rlwinm r0, r0, 0, MSR_FP_BIT+1, MSR_FP_BIT-1
149: stw r0, SS_SRR1(ARG6)
150:
151: .L_fpu_save_no_owner:
152: blr
153:
154:
155: ENTRY(fpu_save_thread, TAG_NO_FRAME_USED)
156:
157: /*
158: * Turn the FPU back on (should this be a separate routine?)
159: */
160:
161: mfmsr r0
162: ori r0, r0, MASK(MSR_FP) /* bit is in low-order 16 */
163: mtmsr r0
164: isync
165:
166: mfsprg ARG7, 0 /* HACK - need to get around r2 problem */
167:
168: lwz ARG6, PP_FPU_PCB(ARG7)
169: /*
170: * See if any thread owns the FPU. If not, we can skip the state save.
171: */
172: cmpwi CR0, ARG6, 0
173: beq- CR0, .L_fpu_save_thread_no_owner
174:
175: /*
176: * Save the current FPU state into the PCB of the thread that owns it.
177: */
178: stfd f0, PCB_FS_F0(ARG6)
179: stfd f1, PCB_FS_F1(ARG6)
180: stfd f2, PCB_FS_F2(ARG6)
181: stfd f3, PCB_FS_F3(ARG6)
182: stfd f4, PCB_FS_F4(ARG6)
183: stfd f5, PCB_FS_F5(ARG6)
184: stfd f6, PCB_FS_F6(ARG6)
185: stfd f7, PCB_FS_F7(ARG6)
186: mffs f0 /* fpscr in f0 low 32 bits*/
187: stfd f8, PCB_FS_F8(ARG6)
188: stfd f9, PCB_FS_F9(ARG6)
189: stfd f10, PCB_FS_F10(ARG6)
190: stfd f11, PCB_FS_F11(ARG6)
191: stfd f12, PCB_FS_F12(ARG6)
192: stfd f13, PCB_FS_F13(ARG6)
193: stfd f14, PCB_FS_F14(ARG6)
194: stfd f15, PCB_FS_F15(ARG6)
195: stfd f0, PCB_FS_FPSCR(ARG6) /* Store junk 32 bits+fpscr */
196: stfd f16, PCB_FS_F16(ARG6)
197: stfd f17, PCB_FS_F17(ARG6)
198: stfd f18, PCB_FS_F18(ARG6)
199: stfd f19, PCB_FS_F19(ARG6)
200: stfd f20, PCB_FS_F20(ARG6)
201: stfd f21, PCB_FS_F21(ARG6)
202: stfd f22, PCB_FS_F22(ARG6)
203: stfd f23, PCB_FS_F23(ARG6)
204: stfd f24, PCB_FS_F24(ARG6)
205: stfd f25, PCB_FS_F25(ARG6)
206: stfd f26, PCB_FS_F26(ARG6)
207: stfd f27, PCB_FS_F27(ARG6)
208: stfd f28, PCB_FS_F28(ARG6)
209: stfd f29, PCB_FS_F29(ARG6)
210: stfd f30, PCB_FS_F30(ARG6)
211: stfd f31, PCB_FS_F31(ARG6)
212:
213: /*
214: * Turn off the FPU for the old owner
215: */
216: lwz r0, SS_SRR1(ARG6)
217: rlwinm r0, r0, 0, MSR_FP_BIT+1, MSR_FP_BIT-1
218: stw r0, SS_SRR1(ARG6)
219:
220: /* Store current PCB address in fpu_pcb to claim fpu for thread */
221: lwz ARG6, PP_CPU_DATA(ARG7)
222: lwz ARG6, CPU_ACTIVE_THREAD(ARG6)
223: lwz ARG6, THREAD_PCB(ARG6)
224: stw ARG6, PP_FPU_PCB(ARG7)
225:
226: .L_fpu_save_thread_no_owner:
227: blr
228:
229: /*
230: * fpu_restore()
231: *
232: * restore the current user thread Floating-Point context in the FPU and
233: * set the FPU ownership to the current user thread.
234: *
235: * This code runs in virtual address mode with interrupts off.
236: *
237: */
238:
239: .text
240: ENTRY(fpu_restore, TAG_NO_FRAME_USED)
241:
242: mfsprg r4, 0 /* load per_proc_info pointer */
243:
244: /* See if the current thread owns the FPU, if so, just return */
245: lwz r3, PP_FPU_PCB(r4)
246:
247: lwz r5, PP_CPU_DATA(r4)
248: lwz r5, CPU_ACTIVE_THREAD(r5)
249: lwz r5, THREAD_PCB(r5)
250:
251: cmpw cr0, r5, r3
252: beq cr0, .L_fpu_restore_ret
253:
254: /* Store current PCB address in fpu_pcb to claim fpu for thread */
255: stw r5, PP_FPU_PCB(r4)
256:
257: /* restore current user thread Floating-Point context */
258: lfd f31, PCB_FS_FPSCR(r5) /* Load junk 32 bits+fpscr */
259: lfd f0, PCB_FS_F0(r5)
260: lfd f1, PCB_FS_F1(r5)
261: lfd f2, PCB_FS_F2(r5)
262: lfd f3, PCB_FS_F3(r5)
263: lfd f4, PCB_FS_F4(r5)
264: lfd f5, PCB_FS_F5(r5)
265: lfd f6, PCB_FS_F6(r5)
266: lfd f7, PCB_FS_F7(r5)
267: mtfsf 0xff, f31 /* fpscr in f0 low 32 bits*/
268: lfd f8, PCB_FS_F8(r5)
269: lfd f9, PCB_FS_F9(r5)
270: lfd f10, PCB_FS_F10(r5)
271: lfd f11, PCB_FS_F11(r5)
272: lfd f12, PCB_FS_F12(r5)
273: lfd f13, PCB_FS_F13(r5)
274: lfd f14, PCB_FS_F14(r5)
275: lfd f15, PCB_FS_F15(r5)
276: lfd f16, PCB_FS_F16(r5)
277: lfd f17, PCB_FS_F17(r5)
278: lfd f18, PCB_FS_F18(r5)
279: lfd f19, PCB_FS_F19(r5)
280: lfd f20, PCB_FS_F20(r5)
281: lfd f21, PCB_FS_F21(r5)
282: lfd f22, PCB_FS_F22(r5)
283: lfd f23, PCB_FS_F23(r5)
284: lfd f24, PCB_FS_F24(r5)
285: lfd f25, PCB_FS_F25(r5)
286: lfd f26, PCB_FS_F26(r5)
287: lfd f27, PCB_FS_F27(r5)
288: lfd f28, PCB_FS_F28(r5)
289: lfd f29, PCB_FS_F29(r5)
290: lfd f30, PCB_FS_F30(r5)
291: lfd f31, PCB_FS_F31(r5)
292:
293: /* Turn back on the FPU in the current user thread saved context */
294: lwz r4, SS_SRR1(r5)
295: ori r4, r4, MASK(MSR_FP) /* bit is in low-order 16 */
296: stw r4, SS_SRR1(r5)
297:
298: .L_fpu_restore_ret:
299: blr
300:
301:
302: /*
303: * fpu_switch()
304: *
305: * Jumped to by the floating-point unavailable exception handler to
306: * switch fpu context in a lazy manner.
307: *
308: * This code is run in virtual address mode with interrupts off.
309: * It is assumed that the pcb in question is in memory
310: *
311: * Upon exit, the code returns to the users context with the MSR_FP for the
312: * previous FPU owner disabled.
313: *
314: * ENTRY: VM switched ON
315: * Interrupts OFF
316: * original r1-3 saved in sprg1-3
317: * original srr0 and srr1 saved in per_proc_info structure
318: * original cr saved in per_proc_info structure
319: * exception type saved in per_proc_info structure
320: * r1 = scratch
321: * r2 = virt addr of per_proc_info
322: * r3 = exception type (one of EXC_...)
323: *
324: * r1 is used as a temporary register throught this code, not as a stack
325: * pointer.
326: *
327: */
328:
329: .text
330: ENTRY(fpu_switch, TAG_NO_FRAME_USED)
331:
332: #if DEBUG
333: lwz r3, PP_SAVE_SRR1(r2)
334: andi. r1, r3, MASK(MSR_PR)
335: bne+ .L_fpu_switch_user
336: bl EXT(fpu_panic)
337: .L_fpu_switch_user:
338: #endif /* DEBUG */
339:
340: /*
341: * Turn the FPU back on
342: */
343: mfmsr r3
344: ori r3, r3, MASK(MSR_FP) /* bit is in low-order 16 */
345: mtmsr r3
346: isync
347:
348: /* See if the current thread owns the FPU, if so, just return */
349: lwz r3, PP_FPU_PCB(r2)
350:
351: lwz r1, PP_CPU_DATA(r2)
352: lwz r1, CPU_ACTIVE_THREAD(r1)
353: lwz r1, THREAD_PCB(r1)
354:
355: cmpw CR0, r1, r3 /* If we own FPU, just return */
356: beq CR0, .L_fpu_switch_return
357: cmpwi CR1, r3, 0 /* If no owner, skip save */
358: beq CR1, .L_fpu_switch_load_state
359:
360: /*
361: * Identical code to that of fpu_save but is inlined
362: * to avoid creating a stack frame etc.
363: */
364: stfd f0, PCB_FS_F0(r3)
365: stfd f1, PCB_FS_F1(r3)
366: stfd f2, PCB_FS_F2(r3)
367: stfd f3, PCB_FS_F3(r3)
368: stfd f4, PCB_FS_F4(r3)
369: stfd f5, PCB_FS_F5(r3)
370: stfd f6, PCB_FS_F6(r3)
371: stfd f7, PCB_FS_F7(r3)
372: mffs f0 /* fpscr in f0 low 32 bits*/
373: stfd f8, PCB_FS_F8(r3)
374: stfd f9, PCB_FS_F9(r3)
375: stfd f10, PCB_FS_F10(r3)
376: stfd f11, PCB_FS_F11(r3)
377: stfd f12, PCB_FS_F12(r3)
378: stfd f13, PCB_FS_F13(r3)
379: stfd f14, PCB_FS_F14(r3)
380: stfd f15, PCB_FS_F15(r3)
381: stfd f0, PCB_FS_FPSCR(r3) /* Store junk 32 bits+fpscr */
382: stfd f16, PCB_FS_F16(r3)
383: stfd f17, PCB_FS_F17(r3)
384: stfd f18, PCB_FS_F18(r3)
385: stfd f19, PCB_FS_F19(r3)
386: stfd f20, PCB_FS_F20(r3)
387: stfd f21, PCB_FS_F21(r3)
388: stfd f22, PCB_FS_F22(r3)
389: stfd f23, PCB_FS_F23(r3)
390: stfd f24, PCB_FS_F24(r3)
391: stfd f25, PCB_FS_F25(r3)
392: stfd f26, PCB_FS_F26(r3)
393: stfd f27, PCB_FS_F27(r3)
394: stfd f28, PCB_FS_F28(r3)
395: stfd f29, PCB_FS_F29(r3)
396: stfd f30, PCB_FS_F30(r3)
397: stfd f31, PCB_FS_F31(r3)
398:
399: stw r0, SS_R0(r1)
400: /*
401: * Turn off the FPU for the old owner
402: */
403: lwz r0, SS_SRR1(r3)
404: rlwinm r0, r0, 0, MSR_FP_BIT+1, MSR_FP_BIT-1
405: stw r0, SS_SRR1(r3)
406:
407: lwz r0, SS_R0(r1)
408:
409: /* Now load in the current threads state */
410:
411: .L_fpu_switch_load_state:
412:
413: /* Store current PCB address in fpu_pcb to claim fpu for thread */
414: stw r1, PP_FPU_PCB(r2)
415:
416: lfd f31, PCB_FS_FPSCR(r1) /* Load junk 32 bits+fpscr */
417: lfd f0, PCB_FS_F0(r1)
418: lfd f1, PCB_FS_F1(r1)
419: lfd f2, PCB_FS_F2(r1)
420: lfd f3, PCB_FS_F3(r1)
421: lfd f4, PCB_FS_F4(r1)
422: lfd f5, PCB_FS_F5(r1)
423: lfd f6, PCB_FS_F6(r1)
424: lfd f7, PCB_FS_F7(r1)
425: mtfsf 0xff, f31 /* fpscr in f0 low 32 bits*/
426: lfd f8, PCB_FS_F8(r1)
427: lfd f9, PCB_FS_F9(r1)
428: lfd f10, PCB_FS_F10(r1)
429: lfd f11, PCB_FS_F11(r1)
430: lfd f12, PCB_FS_F12(r1)
431: lfd f13, PCB_FS_F13(r1)
432: lfd f14, PCB_FS_F14(r1)
433: lfd f15, PCB_FS_F15(r1)
434: lfd f16, PCB_FS_F16(r1)
435: lfd f17, PCB_FS_F17(r1)
436: lfd f18, PCB_FS_F18(r1)
437: lfd f19, PCB_FS_F19(r1)
438: lfd f20, PCB_FS_F20(r1)
439: lfd f21, PCB_FS_F21(r1)
440: lfd f22, PCB_FS_F22(r1)
441: lfd f23, PCB_FS_F23(r1)
442: lfd f24, PCB_FS_F24(r1)
443: lfd f25, PCB_FS_F25(r1)
444: lfd f26, PCB_FS_F26(r1)
445: lfd f27, PCB_FS_F27(r1)
446: lfd f28, PCB_FS_F28(r1)
447: lfd f29, PCB_FS_F29(r1)
448: lfd f30, PCB_FS_F30(r1)
449: lfd f31, PCB_FS_F31(r1)
450:
451: .L_fpu_switch_return:
452:
453: /* the trampoline code takes r1-r3 from sprg1-3, and uses r1-3
454: * as arguments */
455:
456: /* Prepare to rfi to the exception exit routine, which is
457: * in physical address space */
458:
459: addis r3, 0, ha16(EXT(exception_exit))
460: addi r3, r3, lo16(EXT(exception_exit))
461: lwz r3, 0(r3)
462: mtsrr0 r3
463: li r3, MSR_VM_OFF
464: mtsrr1 r3
465:
466:
467: lwz r1, PCB_SR0(r1) /* restore current sr0 */
468:
469: lwz r3, PP_SAVE_CR(r2)
470: mtcrf 0xFF,r3
471: lwz r3, PP_SAVE_SRR1(r2)
472: lwz r2, PP_SAVE_SRR0(r2)
473: /* Enable floating point for the thread we're returning to */
474: ori r3, r3, MASK(MSR_FP) /* bit is in low-order 16 */
475:
476: /* Return to the trapped context */
477: rfi
478:
479: /*
480: * void fpu_disable(void)
481: *
482: * disable the fpu in the current msr
483: *
484: */
485:
486: ENTRY(fpu_disable, TAG_NO_FRAME_USED)
487:
488: /* See if the current thread owns the FPU, if so, just return */
489: mfsprg r2, 0 /* HACK - need to get around r2 problem */
490: lwz r0, PP_FPU_PCB(r2)
491: cmpwi CR1, r0, 0 /* If no owner, skip save */
492: bne CR1, .L_fpu_disable_not
493:
494: mfmsr r0
495: rlwinm r0, r0, 0, MSR_FP_BIT+1, MSR_FP_BIT-1
496: mtmsr r0
497: isync
498: .L_fpu_disable_not:
499: blr
500:
501: ENTRY(fpu_disable_thread, TAG_NO_FRAME_USED)
502:
503: /* Mark the FPU as having no owner now */
504: mfsprg r2, 0 /* HACK - need to get around r2 problem */
505:
506: lwz r0, PP_FPU_PCB(r2)
507: lwz r3, PP_CPU_DATA(r2)
508: lwz r3, CPU_ACTIVE_THREAD(r3)
509: lwz r3, THREAD_PCB(r3)
510:
511: cmpw CR0, r0, r3 /* If we own FPU, disown it */
512: bne CR0, .L_thread_not_own
513:
514: li r0, 0
515: stw r0, PP_FPU_PCB(r2)
516: .L_thread_not_own:
517:
518: mfmsr r0
519: rlwinm r0, r0, 0, MSR_FP_BIT+1, MSR_FP_BIT-1
520: mtmsr r0
521: isync
522: blr
523:
524: /*
525: * void lfs(fpsp,fpdp)
526: *
527: * load the single precision float to the double
528: *
529: * This routine is used by the alignment handler.
530: *
531: */
532: ENTRY(lfs, TAG_NO_FRAME_USED)
533: lfs f1, 0(r3)
534: stfd f1, 0(r4)
535: blr
536:
537: /*
538: * fpsp stfs(fpdp,fpsp)
539: *
540: * store the double precision float to the single
541: *
542: * This routine is used by the alignment handler.
543: *
544: */
545: ENTRY(stfs, TAG_NO_FRAME_USED)
546: lfd f1, 0(r3)
547: stfs f1, 0(r4)
548: blr
549:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.