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