1/* 2 * linux/arch/x86_64/kernel/i387.c 3 * 4 * Copyright (C) 1994 Linus Torvalds 5 * Copyright (C) 2002 Andi Kleen, SuSE Labs 6 * 7 * Pentium III FXSR, SSE support 8 * General FPU state handling cleanups 9 * Gareth Hughes <gareth@valinux.com>, May 2000 10 * 11 * x86-64 rework 2002 Andi Kleen. 12 * Does direct fxsave in and out of user space now for signal handlers. 13 * All the FSAVE<->FXSAVE conversion code has been moved to the 32bit emulation, 14 * the 64bit user space sees a FXSAVE frame directly. 15 */ 16 17#include <linux/config.h> 18#include <linux/sched.h> 19#include <asm/processor.h> 20#include <asm/i387.h> 21#include <asm/sigcontext.h> 22#include <asm/user.h> 23#include <asm/ptrace.h> 24#include <asm/uaccess.h> 25 26extern int exception_trace; 27 28/* 29 * The _current_ task is using the FPU for the first time 30 * so initialize it and set the mxcsr to its default 31 * value at reset if we support XMM instructions and then 32 * remeber the current task has used the FPU. 33 */ 34void init_fpu(void) 35{ 36 struct task_struct *me = current; 37 memset(&me->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct)); 38 me->thread.i387.fxsave.cwd = 0x37f; 39 me->thread.i387.fxsave.mxcsr = 0x1f80; 40 me->used_math = 1; 41} 42 43/* 44 * Signal frame handlers. 45 */ 46 47int save_i387(struct _fpstate *buf) 48{ 49 struct task_struct *tsk = current; 50 int err = 0; 51 52 { 53 extern void bad_user_i387_struct(void); 54 if (sizeof(struct user_i387_struct) != sizeof(tsk->thread.i387.fxsave)) 55 bad_user_i387_struct(); 56 } 57 58 if (!tsk->used_math) 59 return 0; 60 tsk->used_math = 0; /* trigger finit */ 61 if (tsk->flags & PF_USEDFPU) { 62 err = save_i387_checking((struct i387_fxsave_struct *)buf); 63 if (err) { 64 if (exception_trace) 65 printk("%s[%d] unaligned signal floating point context %p\n", 66 tsk->comm, tsk->pid, buf); 67 return err; 68 } 69 stts(); 70 } else { 71 if (__copy_to_user(buf, &tsk->thread.i387.fxsave, 72 sizeof(struct i387_fxsave_struct))) 73 return -1; 74 } 75 return 1; 76} 77 78/* 79 * ptrace request handlers. 80 */ 81 82int get_fpregs(struct user_i387_struct *buf, struct task_struct *tsk) 83{ 84 empty_fpu(tsk); 85 return __copy_to_user((void *)buf, &tsk->thread.i387.fxsave, 86 sizeof(struct user_i387_struct)) ? -EFAULT : 0; 87} 88 89int set_fpregs(struct task_struct *tsk, struct user_i387_struct *buf) 90{ 91 if (__copy_from_user(&tsk->thread.i387.fxsave, buf, 92 sizeof(struct user_i387_struct))) 93 return -EFAULT; 94 /* mxcsr bit 6 and 31-16 must be zero for security reasons. */ 95 tsk->thread.i387.fxsave.mxcsr &= 0xffbf; 96 return 0; 97} 98 99/* 100 * FPU state for core dumps. 101 */ 102 103int dump_fpu( struct pt_regs *regs, struct user_i387_struct *fpu ) 104{ 105 struct task_struct *tsk = current; 106 107 if (!tsk->used_math) 108 return 0; 109 unlazy_fpu(tsk); 110 111 memcpy(fpu, &tsk->thread.i387.fxsave, sizeof(struct user_i387_struct)); 112 return 1; 113} 114