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>
16 struct task_struct
*fpu_state_owner
;
19 * handle an exception due to the FPU being disabled
21 asmlinkage
void fpu_disabled(struct pt_regs
*regs
, enum exception_code code
)
23 struct task_struct
*tsk
= current
;
26 die_if_no_fixup("An FPU Disabled exception happened in"
33 /* transfer the last process's FPU state to memory */
34 if (fpu_state_owner
) {
35 fpu_save(&fpu_state_owner
->thread
.fpu_state
);
36 fpu_state_owner
->thread
.uregs
->epsw
&= ~EPSW_FE
;
39 /* the current process now owns the FPU state */
40 fpu_state_owner
= tsk
;
41 regs
->epsw
|= EPSW_FE
;
43 /* load the FPU with the current process's FPU state or invent a new
44 * clean one if the process doesn't have one */
45 if (is_using_fpu(tsk
)) {
46 fpu_restore(&tsk
->thread
.fpu_state
);
57 info
.si_signo
= SIGFPE
;
59 info
.si_addr
= (void *) tsk
->thread
.uregs
->pc
;
60 info
.si_code
= FPE_FLTINV
;
62 force_sig_info(SIGFPE
, &info
, tsk
);
64 #endif /* CONFIG_FPU */
68 * handle an FPU operational exception
69 * - there's a possibility that if the FPU is asynchronous, the signal might
70 * be meant for a process other than the current one
72 asmlinkage
void fpu_exception(struct pt_regs
*regs
, enum exception_code code
)
74 struct task_struct
*tsk
= fpu_state_owner
;
78 die_if_no_fixup("An FPU Operation exception happened in"
83 die_if_no_fixup("An FPU Operation exception happened,"
84 " but the FPU is not in use",
87 info
.si_signo
= SIGFPE
;
89 info
.si_addr
= (void *) tsk
->thread
.uregs
->pc
;
90 info
.si_code
= FPE_FLTINV
;
96 /* get FPCR (we need to enable the FPU whilst we do this) */
97 asm volatile(" or %1,epsw \n"
98 #ifdef CONFIG_MN10300_PROC_MN103E010
104 #ifdef CONFIG_MN10300_PROC_MN103E010
111 : "i"(EPSW_FE
), "i"(~EPSW_FE
)
114 if (fpcr
& FPCR_EC_Z
)
115 info
.si_code
= FPE_FLTDIV
;
116 else if (fpcr
& FPCR_EC_O
)
117 info
.si_code
= FPE_FLTOVF
;
118 else if (fpcr
& FPCR_EC_U
)
119 info
.si_code
= FPE_FLTUND
;
120 else if (fpcr
& FPCR_EC_I
)
121 info
.si_code
= FPE_FLTRES
;
125 force_sig_info(SIGFPE
, &info
, tsk
);
129 * save the FPU state to a signal context
131 int fpu_setup_sigcontext(struct fpucontext
*fpucontext
)
134 struct task_struct
*tsk
= current
;
136 if (!is_using_fpu(tsk
))
139 /* transfer the current FPU state to memory and cause fpu_init() to be
140 * triggered by the next attempted FPU operation by the current
145 if (fpu_state_owner
== tsk
) {
146 fpu_save(&tsk
->thread
.fpu_state
);
147 fpu_state_owner
->thread
.uregs
->epsw
&= ~EPSW_FE
;
148 fpu_state_owner
= NULL
;
153 /* we no longer have a valid current FPU state */
154 clear_using_fpu(tsk
);
156 /* transfer the saved FPU state onto the userspace stack */
157 if (copy_to_user(fpucontext
,
158 &tsk
->thread
.fpu_state
,
159 min(sizeof(struct fpu_state_struct
),
160 sizeof(struct fpucontext
))))
170 * kill a process's FPU state during restoration after signal handling
172 void fpu_kill_state(struct task_struct
*tsk
)
175 /* disown anything left in the FPU */
178 if (fpu_state_owner
== tsk
) {
179 fpu_state_owner
->thread
.uregs
->epsw
&= ~EPSW_FE
;
180 fpu_state_owner
= NULL
;
185 /* we no longer have a valid current FPU state */
186 clear_using_fpu(tsk
);
190 * restore the FPU state from a signal context
192 int fpu_restore_sigcontext(struct fpucontext
*fpucontext
)
194 struct task_struct
*tsk
= current
;
197 /* load up the old FPU state */
198 ret
= copy_from_user(&tsk
->thread
.fpu_state
,
200 min(sizeof(struct fpu_state_struct
),
201 sizeof(struct fpucontext
)));
209 * fill in the FPU structure for a core dump
211 int dump_fpu(struct pt_regs
*regs
, elf_fpregset_t
*fpreg
)
213 struct task_struct
*tsk
= current
;
216 fpvalid
= is_using_fpu(tsk
);
219 memcpy(fpreg
, &tsk
->thread
.fpu_state
, sizeof(*fpreg
));