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