xref: /linux/arch/sh/kernel/cpu/fpu.c (revision 5499b45190237ca90dd2ac86395cf464fe1f4cc7)
1 #include <linux/sched.h>
2 #include <asm/processor.h>
3 #include <asm/fpu.h>
4 
5 int init_fpu(struct task_struct *tsk)
6 {
7 	if (tsk_used_math(tsk)) {
8 		if ((boot_cpu_data.flags & CPU_HAS_FPU) && tsk == current)
9 			unlazy_fpu(tsk, task_pt_regs(tsk));
10 		return 0;
11 	}
12 
13 	/*
14 	 * Memory allocation at the first usage of the FPU and other state.
15 	 */
16 	if (!tsk->thread.xstate) {
17 		tsk->thread.xstate = kmem_cache_alloc(task_xstate_cachep,
18 						      GFP_KERNEL);
19 		if (!tsk->thread.xstate)
20 			return -ENOMEM;
21 	}
22 
23 	if (boot_cpu_data.flags & CPU_HAS_FPU) {
24 		struct sh_fpu_hard_struct *fp = &tsk->thread.xstate->hardfpu;
25 		memset(fp, 0, xstate_size);
26 		fp->fpscr = FPSCR_INIT;
27 	} else {
28 		struct sh_fpu_soft_struct *fp = &tsk->thread.xstate->softfpu;
29 		memset(fp, 0, xstate_size);
30 		fp->fpscr = FPSCR_INIT;
31 	}
32 
33 	set_stopped_child_used_math(tsk);
34 	return 0;
35 }
36 
37 #ifdef CONFIG_SH_FPU
38 void __fpu_state_restore(void)
39 {
40 	struct task_struct *tsk = current;
41 
42 	restore_fpu(tsk);
43 
44 	task_thread_info(tsk)->status |= TS_USEDFPU;
45 	tsk->fpu_counter++;
46 }
47 
48 void fpu_state_restore(struct pt_regs *regs)
49 {
50 	struct task_struct *tsk = current;
51 
52 	if (unlikely(!user_mode(regs))) {
53 		printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
54 		BUG();
55 		return;
56 	}
57 
58 	if (!tsk_used_math(tsk)) {
59 		local_irq_enable();
60 		/*
61 		 * does a slab alloc which can sleep
62 		 */
63 		if (init_fpu(tsk)) {
64 			/*
65 			 * ran out of memory!
66 			 */
67 			do_group_exit(SIGKILL);
68 			return;
69 		}
70 		local_irq_disable();
71 	}
72 
73 	grab_fpu(regs);
74 
75 	__fpu_state_restore();
76 }
77 
78 BUILD_TRAP_HANDLER(fpu_state_restore)
79 {
80 	TRAP_HANDLER_DECL;
81 
82 	fpu_state_restore(regs);
83 }
84 #endif /* CONFIG_SH_FPU */
85