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