1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2005-2018 Andes Technology Corporation
4 #include <linux/sched.h>
5 #include <linux/signal.h>
6 #include <linux/sched/signal.h>
7 #include <asm/processor.h>
10 #include <asm/bitfield.h>
13 const struct fpu_struct init_fpuregs
= {
14 .fd_regs
= {[0 ... 31] = sNAN64
},
16 #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
21 void save_fpu(struct task_struct
*tsk
)
23 unsigned int fpcfg
, fpcsr
;
26 fpcfg
= ((__nds32__fmfcfg() & FPCFG_mskFREG
) >> FPCFG_offFREG
);
29 asm volatile ("fsdi $fd31, [%0+0xf8]\n\t"
30 "fsdi $fd30, [%0+0xf0]\n\t"
31 "fsdi $fd29, [%0+0xe8]\n\t"
32 "fsdi $fd28, [%0+0xe0]\n\t"
33 "fsdi $fd27, [%0+0xd8]\n\t"
34 "fsdi $fd26, [%0+0xd0]\n\t"
35 "fsdi $fd25, [%0+0xc8]\n\t"
36 "fsdi $fd24, [%0+0xc0]\n\t"
37 "fsdi $fd23, [%0+0xb8]\n\t"
38 "fsdi $fd22, [%0+0xb0]\n\t"
39 "fsdi $fd21, [%0+0xa8]\n\t"
40 "fsdi $fd20, [%0+0xa0]\n\t"
41 "fsdi $fd19, [%0+0x98]\n\t"
42 "fsdi $fd18, [%0+0x90]\n\t"
43 "fsdi $fd17, [%0+0x88]\n\t"
44 "fsdi $fd16, [%0+0x80]\n\t"
46 : "r" (&tsk
->thread
.fpu
)
50 asm volatile ("fsdi $fd15, [%0+0x78]\n\t"
51 "fsdi $fd14, [%0+0x70]\n\t"
52 "fsdi $fd13, [%0+0x68]\n\t"
53 "fsdi $fd12, [%0+0x60]\n\t"
54 "fsdi $fd11, [%0+0x58]\n\t"
55 "fsdi $fd10, [%0+0x50]\n\t"
56 "fsdi $fd9, [%0+0x48]\n\t"
57 "fsdi $fd8, [%0+0x40]\n\t"
59 : "r" (&tsk
->thread
.fpu
)
63 asm volatile ("fsdi $fd7, [%0+0x38]\n\t"
64 "fsdi $fd6, [%0+0x30]\n\t"
65 "fsdi $fd5, [%0+0x28]\n\t"
66 "fsdi $fd4, [%0+0x20]\n\t"
68 : "r" (&tsk
->thread
.fpu
)
72 asm volatile ("fsdi $fd3, [%1+0x18]\n\t"
73 "fsdi $fd2, [%1+0x10]\n\t"
74 "fsdi $fd1, [%1+0x8]\n\t"
75 "fsdi $fd0, [%1+0x0]\n\t"
77 "swi %0, [%1+0x100]\n\t"
79 : "r"(&tsk
->thread
.fpu
)
85 void load_fpu(const struct fpu_struct
*fpregs
)
87 unsigned int fpcfg
, fpcsr
;
90 fpcfg
= ((__nds32__fmfcfg() & FPCFG_mskFREG
) >> FPCFG_offFREG
);
93 asm volatile ("fldi $fd31, [%0+0xf8]\n\t"
94 "fldi $fd30, [%0+0xf0]\n\t"
95 "fldi $fd29, [%0+0xe8]\n\t"
96 "fldi $fd28, [%0+0xe0]\n\t"
97 "fldi $fd27, [%0+0xd8]\n\t"
98 "fldi $fd26, [%0+0xd0]\n\t"
99 "fldi $fd25, [%0+0xc8]\n\t"
100 "fldi $fd24, [%0+0xc0]\n\t"
101 "fldi $fd23, [%0+0xb8]\n\t"
102 "fldi $fd22, [%0+0xb0]\n\t"
103 "fldi $fd21, [%0+0xa8]\n\t"
104 "fldi $fd20, [%0+0xa0]\n\t"
105 "fldi $fd19, [%0+0x98]\n\t"
106 "fldi $fd18, [%0+0x90]\n\t"
107 "fldi $fd17, [%0+0x88]\n\t"
108 "fldi $fd16, [%0+0x80]\n\t"
113 asm volatile ("fldi $fd15, [%0+0x78]\n\t"
114 "fldi $fd14, [%0+0x70]\n\t"
115 "fldi $fd13, [%0+0x68]\n\t"
116 "fldi $fd12, [%0+0x60]\n\t"
117 "fldi $fd11, [%0+0x58]\n\t"
118 "fldi $fd10, [%0+0x50]\n\t"
119 "fldi $fd9, [%0+0x48]\n\t"
120 "fldi $fd8, [%0+0x40]\n\t"
125 asm volatile ("fldi $fd7, [%0+0x38]\n\t"
126 "fldi $fd6, [%0+0x30]\n\t"
127 "fldi $fd5, [%0+0x28]\n\t"
128 "fldi $fd4, [%0+0x20]\n\t"
133 asm volatile ("fldi $fd3, [%1+0x18]\n\t"
134 "fldi $fd2, [%1+0x10]\n\t"
135 "fldi $fd1, [%1+0x8]\n\t"
136 "fldi $fd0, [%1+0x0]\n\t"
137 "lwi %0, [%1+0x100]\n\t"
138 "fmtcsr %0\n\t":"=&r" (fpcsr
)
143 void store_fpu_for_suspend(void)
145 #ifdef CONFIG_LAZY_FPU
146 if (last_task_used_math
!= NULL
)
147 save_fpu(last_task_used_math
);
148 last_task_used_math
= NULL
;
154 clear_fpu(task_pt_regs(current
));
156 inline void do_fpu_context_switch(struct pt_regs
*regs
)
158 /* Enable to use FPU. */
160 if (!user_mode(regs
)) {
161 pr_err("BUG: FPU is used in kernel mode.\n");
166 enable_ptreg_fpu(regs
);
167 #ifdef CONFIG_LAZY_FPU //Lazy FPU is used
168 if (last_task_used_math
== current
)
170 if (last_task_used_math
!= NULL
)
171 /* Other processes fpu state, save away */
172 save_fpu(last_task_used_math
);
173 last_task_used_math
= current
;
176 load_fpu(¤t
->thread
.fpu
);
178 /* First time FPU user. */
179 load_fpu(&init_fpuregs
);
180 #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
181 current
->thread
.fpu
.UDF_IEX_trap
= init_fpuregs
.UDF_IEX_trap
;
188 inline void fill_sigfpe_signo(unsigned int fpcsr
, int *signo
)
190 if (fpcsr
& FPCSR_mskOVFT
)
192 #ifndef CONFIG_SUPPORT_DENORMAL_ARITHMETIC
193 else if (fpcsr
& FPCSR_mskUDFT
)
196 else if (fpcsr
& FPCSR_mskIVOT
)
198 else if (fpcsr
& FPCSR_mskDBZT
)
200 else if (fpcsr
& FPCSR_mskIEXT
)
204 inline void handle_fpu_exception(struct pt_regs
*regs
)
207 int si_code
= 0, si_signo
= SIGFPE
;
208 #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
209 unsigned long redo_except
= FPCSR_mskDNIT
|FPCSR_mskUDFT
|FPCSR_mskIEXT
;
211 unsigned long redo_except
= FPCSR_mskDNIT
;
215 fpcsr
= current
->thread
.fpu
.fpcsr
;
217 if (fpcsr
& redo_except
) {
218 si_signo
= do_fpuemu(regs
, ¤t
->thread
.fpu
);
219 fpcsr
= current
->thread
.fpu
.fpcsr
;
221 current
->thread
.fpu
.fpcsr
&= ~(redo_except
);
224 } else if (fpcsr
& FPCSR_mskRIT
) {
225 if (!user_mode(regs
))
232 fill_sigfpe_signo(fpcsr
, &si_code
);
236 si_code
= ILL_COPROC
;
239 si_code
= BUS_ADRERR
;
245 force_sig_fault(si_signo
, si_code
,
246 (void __user
*)instruction_pointer(regs
));
251 bool do_fpu_exception(unsigned int subtype
, struct pt_regs
*regs
)
254 /* Coprocessor disabled exception */
255 if (subtype
== FPU_DISABLE_EXCEPTION
) {
257 do_fpu_context_switch(regs
);
260 /* Coprocessor exception such as underflow and overflow */
261 else if (subtype
== FPU_EXCEPTION
)
262 handle_fpu_exception(regs
);