diff options
Diffstat (limited to 'arch/x86/kernel/process.c')
-rw-r--r-- | arch/x86/kernel/process.c | 193 |
1 files changed, 191 insertions, 2 deletions
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 23b328edc2b..8c037051b35 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -1,8 +1,8 @@ | |||
1 | #include <linux/errno.h> | 1 | #include <linux/errno.h> |
2 | #include <linux/kernel.h> | 2 | #include <linux/kernel.h> |
3 | #include <linux/mm.h> | 3 | #include <linux/mm.h> |
4 | #include <asm/idle.h> | ||
5 | #include <linux/smp.h> | 4 | #include <linux/smp.h> |
5 | #include <linux/prctl.h> | ||
6 | #include <linux/slab.h> | 6 | #include <linux/slab.h> |
7 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
@@ -11,6 +11,9 @@ | |||
11 | #include <trace/power.h> | 11 | #include <trace/power.h> |
12 | #include <asm/system.h> | 12 | #include <asm/system.h> |
13 | #include <asm/apic.h> | 13 | #include <asm/apic.h> |
14 | #include <asm/idle.h> | ||
15 | #include <asm/uaccess.h> | ||
16 | #include <asm/i387.h> | ||
14 | 17 | ||
15 | unsigned long idle_halt; | 18 | unsigned long idle_halt; |
16 | EXPORT_SYMBOL(idle_halt); | 19 | EXPORT_SYMBOL(idle_halt); |
@@ -59,6 +62,192 @@ void arch_task_cache_init(void) | |||
59 | } | 62 | } |
60 | 63 | ||
61 | /* | 64 | /* |
65 | * Free current thread data structures etc.. | ||
66 | */ | ||
67 | void exit_thread(void) | ||
68 | { | ||
69 | struct task_struct *me = current; | ||
70 | struct thread_struct *t = &me->thread; | ||
71 | |||
72 | if (me->thread.io_bitmap_ptr) { | ||
73 | struct tss_struct *tss = &per_cpu(init_tss, get_cpu()); | ||
74 | |||
75 | kfree(t->io_bitmap_ptr); | ||
76 | t->io_bitmap_ptr = NULL; | ||
77 | clear_thread_flag(TIF_IO_BITMAP); | ||
78 | /* | ||
79 | * Careful, clear this in the TSS too: | ||
80 | */ | ||
81 | memset(tss->io_bitmap, 0xff, t->io_bitmap_max); | ||
82 | t->io_bitmap_max = 0; | ||
83 | put_cpu(); | ||
84 | } | ||
85 | |||
86 | ds_exit_thread(current); | ||
87 | } | ||
88 | |||
89 | void flush_thread(void) | ||
90 | { | ||
91 | struct task_struct *tsk = current; | ||
92 | |||
93 | #ifdef CONFIG_X86_64 | ||
94 | if (test_tsk_thread_flag(tsk, TIF_ABI_PENDING)) { | ||
95 | clear_tsk_thread_flag(tsk, TIF_ABI_PENDING); | ||
96 | if (test_tsk_thread_flag(tsk, TIF_IA32)) { | ||
97 | clear_tsk_thread_flag(tsk, TIF_IA32); | ||
98 | } else { | ||
99 | set_tsk_thread_flag(tsk, TIF_IA32); | ||
100 | current_thread_info()->status |= TS_COMPAT; | ||
101 | } | ||
102 | } | ||
103 | #endif | ||
104 | |||
105 | clear_tsk_thread_flag(tsk, TIF_DEBUG); | ||
106 | |||
107 | tsk->thread.debugreg0 = 0; | ||
108 | tsk->thread.debugreg1 = 0; | ||
109 | tsk->thread.debugreg2 = 0; | ||
110 | tsk->thread.debugreg3 = 0; | ||
111 | tsk->thread.debugreg6 = 0; | ||
112 | tsk->thread.debugreg7 = 0; | ||
113 | memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); | ||
114 | /* | ||
115 | * Forget coprocessor state.. | ||
116 | */ | ||
117 | tsk->fpu_counter = 0; | ||
118 | clear_fpu(tsk); | ||
119 | clear_used_math(); | ||
120 | } | ||
121 | |||
122 | static void hard_disable_TSC(void) | ||
123 | { | ||
124 | write_cr4(read_cr4() | X86_CR4_TSD); | ||
125 | } | ||
126 | |||
127 | void disable_TSC(void) | ||
128 | { | ||
129 | preempt_disable(); | ||
130 | if (!test_and_set_thread_flag(TIF_NOTSC)) | ||
131 | /* | ||
132 | * Must flip the CPU state synchronously with | ||
133 | * TIF_NOTSC in the current running context. | ||
134 | */ | ||
135 | hard_disable_TSC(); | ||
136 | preempt_enable(); | ||
137 | } | ||
138 | |||
139 | static void hard_enable_TSC(void) | ||
140 | { | ||
141 | write_cr4(read_cr4() & ~X86_CR4_TSD); | ||
142 | } | ||
143 | |||
144 | static void enable_TSC(void) | ||
145 | { | ||
146 | preempt_disable(); | ||
147 | if (test_and_clear_thread_flag(TIF_NOTSC)) | ||
148 | /* | ||
149 | * Must flip the CPU state synchronously with | ||
150 | * TIF_NOTSC in the current running context. | ||
151 | */ | ||
152 | hard_enable_TSC(); | ||
153 | preempt_enable(); | ||
154 | } | ||
155 | |||
156 | int get_tsc_mode(unsigned long adr) | ||
157 | { | ||
158 | unsigned int val; | ||
159 | |||
160 | if (test_thread_flag(TIF_NOTSC)) | ||
161 | val = PR_TSC_SIGSEGV; | ||
162 | else | ||
163 | val = PR_TSC_ENABLE; | ||
164 | |||
165 | return put_user(val, (unsigned int __user *)adr); | ||
166 | } | ||
167 | |||
168 | int set_tsc_mode(unsigned int val) | ||
169 | { | ||
170 | if (val == PR_TSC_SIGSEGV) | ||
171 | disable_TSC(); | ||
172 | else if (val == PR_TSC_ENABLE) | ||
173 | enable_TSC(); | ||
174 | else | ||
175 | return -EINVAL; | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, | ||
181 | struct tss_struct *tss) | ||
182 | { | ||
183 | struct thread_struct *prev, *next; | ||
184 | |||
185 | prev = &prev_p->thread; | ||
186 | next = &next_p->thread; | ||
187 | |||
188 | if (test_tsk_thread_flag(next_p, TIF_DS_AREA_MSR) || | ||
189 | test_tsk_thread_flag(prev_p, TIF_DS_AREA_MSR)) | ||
190 | ds_switch_to(prev_p, next_p); | ||
191 | else if (next->debugctlmsr != prev->debugctlmsr) | ||
192 | update_debugctlmsr(next->debugctlmsr); | ||
193 | |||
194 | if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { | ||
195 | set_debugreg(next->debugreg0, 0); | ||
196 | set_debugreg(next->debugreg1, 1); | ||
197 | set_debugreg(next->debugreg2, 2); | ||
198 | set_debugreg(next->debugreg3, 3); | ||
199 | /* no 4 and 5 */ | ||
200 | set_debugreg(next->debugreg6, 6); | ||
201 | set_debugreg(next->debugreg7, 7); | ||
202 | } | ||
203 | |||
204 | if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^ | ||
205 | test_tsk_thread_flag(next_p, TIF_NOTSC)) { | ||
206 | /* prev and next are different */ | ||
207 | if (test_tsk_thread_flag(next_p, TIF_NOTSC)) | ||
208 | hard_disable_TSC(); | ||
209 | else | ||
210 | hard_enable_TSC(); | ||
211 | } | ||
212 | |||
213 | if (test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { | ||
214 | /* | ||
215 | * Copy the relevant range of the IO bitmap. | ||
216 | * Normally this is 128 bytes or less: | ||
217 | */ | ||
218 | memcpy(tss->io_bitmap, next->io_bitmap_ptr, | ||
219 | max(prev->io_bitmap_max, next->io_bitmap_max)); | ||
220 | } else if (test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)) { | ||
221 | /* | ||
222 | * Clear any possible leftover bits: | ||
223 | */ | ||
224 | memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | int sys_fork(struct pt_regs *regs) | ||
229 | { | ||
230 | return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * This is trivial, and on the face of it looks like it | ||
235 | * could equally well be done in user mode. | ||
236 | * | ||
237 | * Not so, for quite unobvious reasons - register pressure. | ||
238 | * In user mode vfork() cannot have a stack frame, and if | ||
239 | * done by calling the "clone()" system call directly, you | ||
240 | * do not have enough call-clobbered registers to hold all | ||
241 | * the information you need. | ||
242 | */ | ||
243 | int sys_vfork(struct pt_regs *regs) | ||
244 | { | ||
245 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, | ||
246 | NULL, NULL); | ||
247 | } | ||
248 | |||
249 | |||
250 | /* | ||
62 | * Idle related variables and functions | 251 | * Idle related variables and functions |
63 | */ | 252 | */ |
64 | unsigned long boot_option_idle_override = 0; | 253 | unsigned long boot_option_idle_override = 0; |
@@ -353,7 +542,7 @@ static void c1e_idle(void) | |||
353 | 542 | ||
354 | void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) | 543 | void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) |
355 | { | 544 | { |
356 | #ifdef CONFIG_X86_SMP | 545 | #ifdef CONFIG_SMP |
357 | if (pm_idle == poll_idle && smp_num_siblings > 1) { | 546 | if (pm_idle == poll_idle && smp_num_siblings > 1) { |
358 | printk(KERN_WARNING "WARNING: polling idle and HT enabled," | 547 | printk(KERN_WARNING "WARNING: polling idle and HT enabled," |
359 | " performance may degrade.\n"); | 548 | " performance may degrade.\n"); |