1 /* MN10300 FPU management
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
11 #include <asm/uaccess.h>
14 #include <asm/exceptions.h>
15 #include <asm/system.h>
17 #ifdef CONFIG_LAZY_SAVE_FPU
18 struct task_struct
*fpu_state_owner
;
22 * error functions in FPU disabled exception
24 asmlinkage
void fpu_disabled_in_kernel(struct pt_regs
*regs
)
26 die_if_no_fixup("An FPU Disabled exception happened in kernel space\n",
27 regs
, EXCEP_FPU_DISABLED
);
31 * handle an FPU operational exception
32 * - there's a possibility that if the FPU is asynchronous, the signal might
33 * be meant for a process other than the current one
35 asmlinkage
void fpu_exception(struct pt_regs
*regs
, enum exception_code code
)
37 struct task_struct
*tsk
= current
;
42 die_if_no_fixup("An FPU Operation exception happened in"
46 if (!is_using_fpu(tsk
))
47 die_if_no_fixup("An FPU Operation exception happened,"
48 " but the FPU is not in use",
51 info
.si_signo
= SIGFPE
;
53 info
.si_addr
= (void *) tsk
->thread
.uregs
->pc
;
54 info
.si_code
= FPE_FLTINV
;
58 fpcr
= tsk
->thread
.fpu_state
.fpcr
;
61 info
.si_code
= FPE_FLTDIV
;
62 else if (fpcr
& FPCR_EC_O
)
63 info
.si_code
= FPE_FLTOVF
;
64 else if (fpcr
& FPCR_EC_U
)
65 info
.si_code
= FPE_FLTUND
;
66 else if (fpcr
& FPCR_EC_I
)
67 info
.si_code
= FPE_FLTRES
;
69 force_sig_info(SIGFPE
, &info
, tsk
);
73 * save the FPU state to a signal context
75 int fpu_setup_sigcontext(struct fpucontext
*fpucontext
)
77 struct task_struct
*tsk
= current
;
79 if (!is_using_fpu(tsk
))
82 /* transfer the current FPU state to memory and cause fpu_init() to be
83 * triggered by the next attempted FPU operation by the current
88 #ifndef CONFIG_LAZY_SAVE_FPU
89 if (tsk
->thread
.fpu_flags
& THREAD_HAS_FPU
) {
90 fpu_save(&tsk
->thread
.fpu_state
);
91 tsk
->thread
.uregs
->epsw
&= ~EPSW_FE
;
92 tsk
->thread
.fpu_flags
&= ~THREAD_HAS_FPU
;
94 #else /* !CONFIG_LAZY_SAVE_FPU */
95 if (fpu_state_owner
== tsk
) {
96 fpu_save(&tsk
->thread
.fpu_state
);
97 fpu_state_owner
->thread
.uregs
->epsw
&= ~EPSW_FE
;
98 fpu_state_owner
= NULL
;
100 #endif /* !CONFIG_LAZY_SAVE_FPU */
104 /* we no longer have a valid current FPU state */
105 clear_using_fpu(tsk
);
107 /* transfer the saved FPU state onto the userspace stack */
108 if (copy_to_user(fpucontext
,
109 &tsk
->thread
.fpu_state
,
110 min(sizeof(struct fpu_state_struct
),
111 sizeof(struct fpucontext
))))
118 * kill a process's FPU state during restoration after signal handling
120 void fpu_kill_state(struct task_struct
*tsk
)
122 /* disown anything left in the FPU */
125 #ifndef CONFIG_LAZY_SAVE_FPU
126 if (tsk
->thread
.fpu_flags
& THREAD_HAS_FPU
) {
127 tsk
->thread
.uregs
->epsw
&= ~EPSW_FE
;
128 tsk
->thread
.fpu_flags
&= ~THREAD_HAS_FPU
;
130 #else /* !CONFIG_LAZY_SAVE_FPU */
131 if (fpu_state_owner
== tsk
) {
132 fpu_state_owner
->thread
.uregs
->epsw
&= ~EPSW_FE
;
133 fpu_state_owner
= NULL
;
135 #endif /* !CONFIG_LAZY_SAVE_FPU */
139 /* we no longer have a valid current FPU state */
140 clear_using_fpu(tsk
);
144 * restore the FPU state from a signal context
146 int fpu_restore_sigcontext(struct fpucontext
*fpucontext
)
148 struct task_struct
*tsk
= current
;
151 /* load up the old FPU state */
152 ret
= copy_from_user(&tsk
->thread
.fpu_state
, fpucontext
,
153 min(sizeof(struct fpu_state_struct
),
154 sizeof(struct fpucontext
)));
162 * fill in the FPU structure for a core dump
164 int dump_fpu(struct pt_regs
*regs
, elf_fpregset_t
*fpreg
)
166 struct task_struct
*tsk
= current
;
169 fpvalid
= is_using_fpu(tsk
);
172 memcpy(fpreg
, &tsk
->thread
.fpu_state
, sizeof(*fpreg
));