diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2007-10-11 05:17:24 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2007-10-11 05:17:24 -0400 |
commit | 250c22777fe1ccd7ac588579a6c16db4c0161cc5 (patch) | |
tree | 55c317efb7d792ec6fdae1d1937c67a502c48dec /arch/x86/kernel/i387_64.c | |
parent | 2db55d344e529492545cb3b755c7e9ba8e4fa94e (diff) |
x86_64: move kernel
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/i387_64.c')
-rw-r--r-- | arch/x86/kernel/i387_64.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/arch/x86/kernel/i387_64.c b/arch/x86/kernel/i387_64.c new file mode 100644 index 000000000000..1d58c13bc6bc --- /dev/null +++ b/arch/x86/kernel/i387_64.c | |||
@@ -0,0 +1,151 @@ | |||
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/sched.h> | ||
18 | #include <linux/init.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 | |||
26 | unsigned int mxcsr_feature_mask __read_mostly = 0xffffffff; | ||
27 | |||
28 | void mxcsr_feature_mask_init(void) | ||
29 | { | ||
30 | unsigned int mask; | ||
31 | clts(); | ||
32 | memset(¤t->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct)); | ||
33 | asm volatile("fxsave %0" : : "m" (current->thread.i387.fxsave)); | ||
34 | mask = current->thread.i387.fxsave.mxcsr_mask; | ||
35 | if (mask == 0) mask = 0x0000ffbf; | ||
36 | mxcsr_feature_mask &= mask; | ||
37 | stts(); | ||
38 | } | ||
39 | |||
40 | /* | ||
41 | * Called at bootup to set up the initial FPU state that is later cloned | ||
42 | * into all processes. | ||
43 | */ | ||
44 | void __cpuinit fpu_init(void) | ||
45 | { | ||
46 | unsigned long oldcr0 = read_cr0(); | ||
47 | extern void __bad_fxsave_alignment(void); | ||
48 | |||
49 | if (offsetof(struct task_struct, thread.i387.fxsave) & 15) | ||
50 | __bad_fxsave_alignment(); | ||
51 | set_in_cr4(X86_CR4_OSFXSR); | ||
52 | set_in_cr4(X86_CR4_OSXMMEXCPT); | ||
53 | |||
54 | write_cr0(oldcr0 & ~((1UL<<3)|(1UL<<2))); /* clear TS and EM */ | ||
55 | |||
56 | mxcsr_feature_mask_init(); | ||
57 | /* clean state in init */ | ||
58 | current_thread_info()->status = 0; | ||
59 | clear_used_math(); | ||
60 | } | ||
61 | |||
62 | void init_fpu(struct task_struct *child) | ||
63 | { | ||
64 | if (tsk_used_math(child)) { | ||
65 | if (child == current) | ||
66 | unlazy_fpu(child); | ||
67 | return; | ||
68 | } | ||
69 | memset(&child->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct)); | ||
70 | child->thread.i387.fxsave.cwd = 0x37f; | ||
71 | child->thread.i387.fxsave.mxcsr = 0x1f80; | ||
72 | /* only the device not available exception or ptrace can call init_fpu */ | ||
73 | set_stopped_child_used_math(child); | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Signal frame handlers. | ||
78 | */ | ||
79 | |||
80 | int save_i387(struct _fpstate __user *buf) | ||
81 | { | ||
82 | struct task_struct *tsk = current; | ||
83 | int err = 0; | ||
84 | |||
85 | BUILD_BUG_ON(sizeof(struct user_i387_struct) != | ||
86 | sizeof(tsk->thread.i387.fxsave)); | ||
87 | |||
88 | if ((unsigned long)buf % 16) | ||
89 | printk("save_i387: bad fpstate %p\n",buf); | ||
90 | |||
91 | if (!used_math()) | ||
92 | return 0; | ||
93 | clear_used_math(); /* trigger finit */ | ||
94 | if (task_thread_info(tsk)->status & TS_USEDFPU) { | ||
95 | err = save_i387_checking((struct i387_fxsave_struct __user *)buf); | ||
96 | if (err) return err; | ||
97 | stts(); | ||
98 | } else { | ||
99 | if (__copy_to_user(buf, &tsk->thread.i387.fxsave, | ||
100 | sizeof(struct i387_fxsave_struct))) | ||
101 | return -1; | ||
102 | } | ||
103 | return 1; | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * ptrace request handlers. | ||
108 | */ | ||
109 | |||
110 | int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *tsk) | ||
111 | { | ||
112 | init_fpu(tsk); | ||
113 | return __copy_to_user(buf, &tsk->thread.i387.fxsave, | ||
114 | sizeof(struct user_i387_struct)) ? -EFAULT : 0; | ||
115 | } | ||
116 | |||
117 | int set_fpregs(struct task_struct *tsk, struct user_i387_struct __user *buf) | ||
118 | { | ||
119 | if (__copy_from_user(&tsk->thread.i387.fxsave, buf, | ||
120 | sizeof(struct user_i387_struct))) | ||
121 | return -EFAULT; | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * FPU state for core dumps. | ||
127 | */ | ||
128 | |||
129 | int dump_fpu( struct pt_regs *regs, struct user_i387_struct *fpu ) | ||
130 | { | ||
131 | struct task_struct *tsk = current; | ||
132 | |||
133 | if (!used_math()) | ||
134 | return 0; | ||
135 | |||
136 | unlazy_fpu(tsk); | ||
137 | memcpy(fpu, &tsk->thread.i387.fxsave, sizeof(struct user_i387_struct)); | ||
138 | return 1; | ||
139 | } | ||
140 | |||
141 | int dump_task_fpu(struct task_struct *tsk, struct user_i387_struct *fpu) | ||
142 | { | ||
143 | int fpvalid = !!tsk_used_math(tsk); | ||
144 | |||
145 | if (fpvalid) { | ||
146 | if (tsk == current) | ||
147 | unlazy_fpu(tsk); | ||
148 | memcpy(fpu, &tsk->thread.i387.fxsave, sizeof(struct user_i387_struct)); | ||
149 | } | ||
150 | return fpvalid; | ||
151 | } | ||