aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/process.c')
-rw-r--r--arch/x86/kernel/process.c193
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
15unsigned long idle_halt; 18unsigned long idle_halt;
16EXPORT_SYMBOL(idle_halt); 19EXPORT_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 */
67void 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
89void 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
122static void hard_disable_TSC(void)
123{
124 write_cr4(read_cr4() | X86_CR4_TSD);
125}
126
127void 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
139static void hard_enable_TSC(void)
140{
141 write_cr4(read_cr4() & ~X86_CR4_TSD);
142}
143
144static 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
156int 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
168int 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
180void __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
228int 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 */
243int 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 */
64unsigned long boot_option_idle_override = 0; 253unsigned long boot_option_idle_override = 0;
@@ -353,7 +542,7 @@ static void c1e_idle(void)
353 542
354void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) 543void __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");