aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/kernel/fpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mn10300/kernel/fpu.c')
-rw-r--r--arch/mn10300/kernel/fpu.c141
1 files changed, 56 insertions, 85 deletions
diff --git a/arch/mn10300/kernel/fpu.c b/arch/mn10300/kernel/fpu.c
index e705f25ad5ff..5f9c3fa19a85 100644
--- a/arch/mn10300/kernel/fpu.c
+++ b/arch/mn10300/kernel/fpu.c
@@ -12,56 +12,19 @@
12#include <asm/fpu.h> 12#include <asm/fpu.h>
13#include <asm/elf.h> 13#include <asm/elf.h>
14#include <asm/exceptions.h> 14#include <asm/exceptions.h>
15#include <asm/system.h>
15 16
17#ifdef CONFIG_LAZY_SAVE_FPU
16struct task_struct *fpu_state_owner; 18struct task_struct *fpu_state_owner;
19#endif
17 20
18/* 21/*
19 * handle an exception due to the FPU being disabled 22 * error functions in FPU disabled exception
20 */ 23 */
21asmlinkage void fpu_disabled(struct pt_regs *regs, enum exception_code code) 24asmlinkage void fpu_disabled_in_kernel(struct pt_regs *regs)
22{ 25{
23 struct task_struct *tsk = current; 26 die_if_no_fixup("An FPU Disabled exception happened in kernel space\n",
24 27 regs, EXCEP_FPU_DISABLED);
25 if (!user_mode(regs))
26 die_if_no_fixup("An FPU Disabled exception happened in"
27 " kernel space\n",
28 regs, code);
29
30#ifdef CONFIG_FPU
31 preempt_disable();
32
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;
37 }
38
39 /* the current process now owns the FPU state */
40 fpu_state_owner = tsk;
41 regs->epsw |= EPSW_FE;
42
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);
47 } else {
48 fpu_init_state();
49 set_using_fpu(tsk);
50 }
51
52 preempt_enable();
53#else
54 {
55 siginfo_t info;
56
57 info.si_signo = SIGFPE;
58 info.si_errno = 0;
59 info.si_addr = (void *) tsk->thread.uregs->pc;
60 info.si_code = FPE_FLTINV;
61
62 force_sig_info(SIGFPE, &info, tsk);
63 }
64#endif /* CONFIG_FPU */
65} 28}
66 29
67/* 30/*
@@ -71,15 +34,16 @@ asmlinkage void fpu_disabled(struct pt_regs *regs, enum exception_code code)
71 */ 34 */
72asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code) 35asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
73{ 36{
74 struct task_struct *tsk = fpu_state_owner; 37 struct task_struct *tsk = current;
75 siginfo_t info; 38 siginfo_t info;
39 u32 fpcr;
76 40
77 if (!user_mode(regs)) 41 if (!user_mode(regs))
78 die_if_no_fixup("An FPU Operation exception happened in" 42 die_if_no_fixup("An FPU Operation exception happened in"
79 " kernel space\n", 43 " kernel space\n",
80 regs, code); 44 regs, code);
81 45
82 if (!tsk) 46 if (!is_using_fpu(tsk))
83 die_if_no_fixup("An FPU Operation exception happened," 47 die_if_no_fixup("An FPU Operation exception happened,"
84 " but the FPU is not in use", 48 " but the FPU is not in use",
85 regs, code); 49 regs, code);
@@ -89,48 +53,45 @@ asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
89 info.si_addr = (void *) tsk->thread.uregs->pc; 53 info.si_addr = (void *) tsk->thread.uregs->pc;
90 info.si_code = FPE_FLTINV; 54 info.si_code = FPE_FLTINV;
91 55
92#ifdef CONFIG_FPU 56 unlazy_fpu(tsk);
93 {
94 u32 fpcr;
95 57
96 /* get FPCR (we need to enable the FPU whilst we do this) */ 58 fpcr = tsk->thread.fpu_state.fpcr;
97 asm volatile(" or %1,epsw \n" 59
98#ifdef CONFIG_MN10300_PROC_MN103E010 60 if (fpcr & FPCR_EC_Z)
99 " nop \n" 61 info.si_code = FPE_FLTDIV;
100 " nop \n" 62 else if (fpcr & FPCR_EC_O)
101 " nop \n" 63 info.si_code = FPE_FLTOVF;
102#endif 64 else if (fpcr & FPCR_EC_U)
103 " fmov fpcr,%0 \n" 65 info.si_code = FPE_FLTUND;
104#ifdef CONFIG_MN10300_PROC_MN103E010 66 else if (fpcr & FPCR_EC_I)
105 " nop \n" 67 info.si_code = FPE_FLTRES;
106 " nop \n"
107 " nop \n"
108#endif
109 " and %2,epsw \n"
110 : "=&d"(fpcr)
111 : "i"(EPSW_FE), "i"(~EPSW_FE)
112 );
113
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;
122 }
123#endif
124 68
125 force_sig_info(SIGFPE, &info, tsk); 69 force_sig_info(SIGFPE, &info, tsk);
126} 70}
127 71
128/* 72/*
73 * handle an FPU invalid_op exception
74 * - Derived from DO_EINFO() macro in arch/mn10300/kernel/traps.c
75 */
76asmlinkage void fpu_invalid_op(struct pt_regs *regs, enum exception_code code)
77{
78 siginfo_t info;
79
80 if (!user_mode(regs))
81 die_if_no_fixup("FPU invalid opcode", regs, code);
82
83 info.si_signo = SIGILL;
84 info.si_errno = 0;
85 info.si_code = ILL_COPROC;
86 info.si_addr = (void *) regs->pc;
87 force_sig_info(info.si_signo, &info, current);
88}
89
90/*
129 * save the FPU state to a signal context 91 * save the FPU state to a signal context
130 */ 92 */
131int fpu_setup_sigcontext(struct fpucontext *fpucontext) 93int fpu_setup_sigcontext(struct fpucontext *fpucontext)
132{ 94{
133#ifdef CONFIG_FPU
134 struct task_struct *tsk = current; 95 struct task_struct *tsk = current;
135 96
136 if (!is_using_fpu(tsk)) 97 if (!is_using_fpu(tsk))
@@ -142,11 +103,19 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext)
142 */ 103 */
143 preempt_disable(); 104 preempt_disable();
144 105
106#ifndef CONFIG_LAZY_SAVE_FPU
107 if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
108 fpu_save(&tsk->thread.fpu_state);
109 tsk->thread.uregs->epsw &= ~EPSW_FE;
110 tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
111 }
112#else /* !CONFIG_LAZY_SAVE_FPU */
145 if (fpu_state_owner == tsk) { 113 if (fpu_state_owner == tsk) {
146 fpu_save(&tsk->thread.fpu_state); 114 fpu_save(&tsk->thread.fpu_state);
147 fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE; 115 fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
148 fpu_state_owner = NULL; 116 fpu_state_owner = NULL;
149 } 117 }
118#endif /* !CONFIG_LAZY_SAVE_FPU */
150 119
151 preempt_enable(); 120 preempt_enable();
152 121
@@ -161,9 +130,6 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext)
161 return -1; 130 return -1;
162 131
163 return 1; 132 return 1;
164#else
165 return 0;
166#endif
167} 133}
168 134
169/* 135/*
@@ -171,17 +137,23 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext)
171 */ 137 */
172void fpu_kill_state(struct task_struct *tsk) 138void fpu_kill_state(struct task_struct *tsk)
173{ 139{
174#ifdef CONFIG_FPU
175 /* disown anything left in the FPU */ 140 /* disown anything left in the FPU */
176 preempt_disable(); 141 preempt_disable();
177 142
143#ifndef CONFIG_LAZY_SAVE_FPU
144 if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
145 tsk->thread.uregs->epsw &= ~EPSW_FE;
146 tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
147 }
148#else /* !CONFIG_LAZY_SAVE_FPU */
178 if (fpu_state_owner == tsk) { 149 if (fpu_state_owner == tsk) {
179 fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE; 150 fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
180 fpu_state_owner = NULL; 151 fpu_state_owner = NULL;
181 } 152 }
153#endif /* !CONFIG_LAZY_SAVE_FPU */
182 154
183 preempt_enable(); 155 preempt_enable();
184#endif 156
185 /* we no longer have a valid current FPU state */ 157 /* we no longer have a valid current FPU state */
186 clear_using_fpu(tsk); 158 clear_using_fpu(tsk);
187} 159}
@@ -195,8 +167,7 @@ int fpu_restore_sigcontext(struct fpucontext *fpucontext)
195 int ret; 167 int ret;
196 168
197 /* load up the old FPU state */ 169 /* load up the old FPU state */
198 ret = copy_from_user(&tsk->thread.fpu_state, 170 ret = copy_from_user(&tsk->thread.fpu_state, fpucontext,
199 fpucontext,
200 min(sizeof(struct fpu_state_struct), 171 min(sizeof(struct fpu_state_struct),
201 sizeof(struct fpucontext))); 172 sizeof(struct fpucontext)));
202 if (!ret) 173 if (!ret)