diff options
Diffstat (limited to 'arch/x86/kernel/process_32.c')
-rw-r--r-- | arch/x86/kernel/process_32.c | 244 |
1 files changed, 29 insertions, 215 deletions
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index a546f55c77b4..14014d766cad 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <stdarg.h> | 12 | #include <stdarg.h> |
13 | 13 | ||
14 | #include <linux/stackprotector.h> | ||
14 | #include <linux/cpu.h> | 15 | #include <linux/cpu.h> |
15 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
16 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
@@ -66,9 +67,6 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | |||
66 | DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; | 67 | DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; |
67 | EXPORT_PER_CPU_SYMBOL(current_task); | 68 | EXPORT_PER_CPU_SYMBOL(current_task); |
68 | 69 | ||
69 | DEFINE_PER_CPU(int, cpu_number); | ||
70 | EXPORT_PER_CPU_SYMBOL(cpu_number); | ||
71 | |||
72 | /* | 70 | /* |
73 | * Return saved PC of a blocked thread. | 71 | * Return saved PC of a blocked thread. |
74 | */ | 72 | */ |
@@ -94,6 +92,15 @@ void cpu_idle(void) | |||
94 | { | 92 | { |
95 | int cpu = smp_processor_id(); | 93 | int cpu = smp_processor_id(); |
96 | 94 | ||
95 | /* | ||
96 | * If we're the non-boot CPU, nothing set the stack canary up | ||
97 | * for us. CPU0 already has it initialized but no harm in | ||
98 | * doing it again. This is a good place for updating it, as | ||
99 | * we wont ever return from this function (so the invalid | ||
100 | * canaries already on the stack wont ever trigger). | ||
101 | */ | ||
102 | boot_init_stack_canary(); | ||
103 | |||
97 | current_thread_info()->status |= TS_POLLING; | 104 | current_thread_info()->status |= TS_POLLING; |
98 | 105 | ||
99 | /* endless idle loop with no priority at all */ | 106 | /* endless idle loop with no priority at all */ |
@@ -104,14 +111,10 @@ void cpu_idle(void) | |||
104 | check_pgt_cache(); | 111 | check_pgt_cache(); |
105 | rmb(); | 112 | rmb(); |
106 | 113 | ||
107 | if (rcu_pending(cpu)) | ||
108 | rcu_check_callbacks(cpu, 0); | ||
109 | |||
110 | if (cpu_is_offline(cpu)) | 114 | if (cpu_is_offline(cpu)) |
111 | play_dead(); | 115 | play_dead(); |
112 | 116 | ||
113 | local_irq_disable(); | 117 | local_irq_disable(); |
114 | __get_cpu_var(irq_stat).idle_timestamp = jiffies; | ||
115 | /* Don't trace irqs off for idle */ | 118 | /* Don't trace irqs off for idle */ |
116 | stop_critical_timings(); | 119 | stop_critical_timings(); |
117 | pm_idle(); | 120 | pm_idle(); |
@@ -135,7 +138,7 @@ void __show_regs(struct pt_regs *regs, int all) | |||
135 | if (user_mode_vm(regs)) { | 138 | if (user_mode_vm(regs)) { |
136 | sp = regs->sp; | 139 | sp = regs->sp; |
137 | ss = regs->ss & 0xffff; | 140 | ss = regs->ss & 0xffff; |
138 | savesegment(gs, gs); | 141 | gs = get_user_gs(regs); |
139 | } else { | 142 | } else { |
140 | sp = (unsigned long) (®s->sp); | 143 | sp = (unsigned long) (®s->sp); |
141 | savesegment(ss, ss); | 144 | savesegment(ss, ss); |
@@ -216,6 +219,7 @@ int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | |||
216 | regs.ds = __USER_DS; | 219 | regs.ds = __USER_DS; |
217 | regs.es = __USER_DS; | 220 | regs.es = __USER_DS; |
218 | regs.fs = __KERNEL_PERCPU; | 221 | regs.fs = __KERNEL_PERCPU; |
222 | regs.gs = __KERNEL_STACK_CANARY; | ||
219 | regs.orig_ax = -1; | 223 | regs.orig_ax = -1; |
220 | regs.ip = (unsigned long) kernel_thread_helper; | 224 | regs.ip = (unsigned long) kernel_thread_helper; |
221 | regs.cs = __KERNEL_CS | get_kernel_rpl(); | 225 | regs.cs = __KERNEL_CS | get_kernel_rpl(); |
@@ -226,55 +230,6 @@ int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | |||
226 | } | 230 | } |
227 | EXPORT_SYMBOL(kernel_thread); | 231 | EXPORT_SYMBOL(kernel_thread); |
228 | 232 | ||
229 | /* | ||
230 | * Free current thread data structures etc.. | ||
231 | */ | ||
232 | void exit_thread(void) | ||
233 | { | ||
234 | /* The process may have allocated an io port bitmap... nuke it. */ | ||
235 | if (unlikely(test_thread_flag(TIF_IO_BITMAP))) { | ||
236 | struct task_struct *tsk = current; | ||
237 | struct thread_struct *t = &tsk->thread; | ||
238 | int cpu = get_cpu(); | ||
239 | struct tss_struct *tss = &per_cpu(init_tss, cpu); | ||
240 | |||
241 | kfree(t->io_bitmap_ptr); | ||
242 | t->io_bitmap_ptr = NULL; | ||
243 | clear_thread_flag(TIF_IO_BITMAP); | ||
244 | /* | ||
245 | * Careful, clear this in the TSS too: | ||
246 | */ | ||
247 | memset(tss->io_bitmap, 0xff, tss->io_bitmap_max); | ||
248 | t->io_bitmap_max = 0; | ||
249 | tss->io_bitmap_owner = NULL; | ||
250 | tss->io_bitmap_max = 0; | ||
251 | tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; | ||
252 | put_cpu(); | ||
253 | } | ||
254 | |||
255 | ds_exit_thread(current); | ||
256 | } | ||
257 | |||
258 | void flush_thread(void) | ||
259 | { | ||
260 | struct task_struct *tsk = current; | ||
261 | |||
262 | tsk->thread.debugreg0 = 0; | ||
263 | tsk->thread.debugreg1 = 0; | ||
264 | tsk->thread.debugreg2 = 0; | ||
265 | tsk->thread.debugreg3 = 0; | ||
266 | tsk->thread.debugreg6 = 0; | ||
267 | tsk->thread.debugreg7 = 0; | ||
268 | memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); | ||
269 | clear_tsk_thread_flag(tsk, TIF_DEBUG); | ||
270 | /* | ||
271 | * Forget coprocessor state.. | ||
272 | */ | ||
273 | tsk->fpu_counter = 0; | ||
274 | clear_fpu(tsk); | ||
275 | clear_used_math(); | ||
276 | } | ||
277 | |||
278 | void release_thread(struct task_struct *dead_task) | 233 | void release_thread(struct task_struct *dead_task) |
279 | { | 234 | { |
280 | BUG_ON(dead_task->mm); | 235 | BUG_ON(dead_task->mm); |
@@ -308,7 +263,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
308 | 263 | ||
309 | p->thread.ip = (unsigned long) ret_from_fork; | 264 | p->thread.ip = (unsigned long) ret_from_fork; |
310 | 265 | ||
311 | savesegment(gs, p->thread.gs); | 266 | task_user_gs(p) = get_user_gs(regs); |
312 | 267 | ||
313 | tsk = current; | 268 | tsk = current; |
314 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { | 269 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { |
@@ -346,7 +301,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
346 | void | 301 | void |
347 | start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) | 302 | start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) |
348 | { | 303 | { |
349 | __asm__("movl %0, %%gs" : : "r"(0)); | 304 | set_user_gs(regs, 0); |
350 | regs->fs = 0; | 305 | regs->fs = 0; |
351 | set_fs(USER_DS); | 306 | set_fs(USER_DS); |
352 | regs->ds = __USER_DS; | 307 | regs->ds = __USER_DS; |
@@ -362,127 +317,6 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) | |||
362 | } | 317 | } |
363 | EXPORT_SYMBOL_GPL(start_thread); | 318 | EXPORT_SYMBOL_GPL(start_thread); |
364 | 319 | ||
365 | static void hard_disable_TSC(void) | ||
366 | { | ||
367 | write_cr4(read_cr4() | X86_CR4_TSD); | ||
368 | } | ||
369 | |||
370 | void disable_TSC(void) | ||
371 | { | ||
372 | preempt_disable(); | ||
373 | if (!test_and_set_thread_flag(TIF_NOTSC)) | ||
374 | /* | ||
375 | * Must flip the CPU state synchronously with | ||
376 | * TIF_NOTSC in the current running context. | ||
377 | */ | ||
378 | hard_disable_TSC(); | ||
379 | preempt_enable(); | ||
380 | } | ||
381 | |||
382 | static void hard_enable_TSC(void) | ||
383 | { | ||
384 | write_cr4(read_cr4() & ~X86_CR4_TSD); | ||
385 | } | ||
386 | |||
387 | static void enable_TSC(void) | ||
388 | { | ||
389 | preempt_disable(); | ||
390 | if (test_and_clear_thread_flag(TIF_NOTSC)) | ||
391 | /* | ||
392 | * Must flip the CPU state synchronously with | ||
393 | * TIF_NOTSC in the current running context. | ||
394 | */ | ||
395 | hard_enable_TSC(); | ||
396 | preempt_enable(); | ||
397 | } | ||
398 | |||
399 | int get_tsc_mode(unsigned long adr) | ||
400 | { | ||
401 | unsigned int val; | ||
402 | |||
403 | if (test_thread_flag(TIF_NOTSC)) | ||
404 | val = PR_TSC_SIGSEGV; | ||
405 | else | ||
406 | val = PR_TSC_ENABLE; | ||
407 | |||
408 | return put_user(val, (unsigned int __user *)adr); | ||
409 | } | ||
410 | |||
411 | int set_tsc_mode(unsigned int val) | ||
412 | { | ||
413 | if (val == PR_TSC_SIGSEGV) | ||
414 | disable_TSC(); | ||
415 | else if (val == PR_TSC_ENABLE) | ||
416 | enable_TSC(); | ||
417 | else | ||
418 | return -EINVAL; | ||
419 | |||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static noinline void | ||
424 | __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, | ||
425 | struct tss_struct *tss) | ||
426 | { | ||
427 | struct thread_struct *prev, *next; | ||
428 | |||
429 | prev = &prev_p->thread; | ||
430 | next = &next_p->thread; | ||
431 | |||
432 | if (test_tsk_thread_flag(next_p, TIF_DS_AREA_MSR) || | ||
433 | test_tsk_thread_flag(prev_p, TIF_DS_AREA_MSR)) | ||
434 | ds_switch_to(prev_p, next_p); | ||
435 | else if (next->debugctlmsr != prev->debugctlmsr) | ||
436 | update_debugctlmsr(next->debugctlmsr); | ||
437 | |||
438 | if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { | ||
439 | set_debugreg(next->debugreg0, 0); | ||
440 | set_debugreg(next->debugreg1, 1); | ||
441 | set_debugreg(next->debugreg2, 2); | ||
442 | set_debugreg(next->debugreg3, 3); | ||
443 | /* no 4 and 5 */ | ||
444 | set_debugreg(next->debugreg6, 6); | ||
445 | set_debugreg(next->debugreg7, 7); | ||
446 | } | ||
447 | |||
448 | if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^ | ||
449 | test_tsk_thread_flag(next_p, TIF_NOTSC)) { | ||
450 | /* prev and next are different */ | ||
451 | if (test_tsk_thread_flag(next_p, TIF_NOTSC)) | ||
452 | hard_disable_TSC(); | ||
453 | else | ||
454 | hard_enable_TSC(); | ||
455 | } | ||
456 | |||
457 | if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { | ||
458 | /* | ||
459 | * Disable the bitmap via an invalid offset. We still cache | ||
460 | * the previous bitmap owner and the IO bitmap contents: | ||
461 | */ | ||
462 | tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; | ||
463 | return; | ||
464 | } | ||
465 | |||
466 | if (likely(next == tss->io_bitmap_owner)) { | ||
467 | /* | ||
468 | * Previous owner of the bitmap (hence the bitmap content) | ||
469 | * matches the next task, we dont have to do anything but | ||
470 | * to set a valid offset in the TSS: | ||
471 | */ | ||
472 | tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; | ||
473 | return; | ||
474 | } | ||
475 | /* | ||
476 | * Lazy TSS's I/O bitmap copy. We set an invalid offset here | ||
477 | * and we let the task to get a GPF in case an I/O instruction | ||
478 | * is performed. The handler of the GPF will verify that the | ||
479 | * faulting task has a valid I/O bitmap and, it true, does the | ||
480 | * real copy and restart the instruction. This will save us | ||
481 | * redundant copies when the currently switched task does not | ||
482 | * perform any I/O during its timeslice. | ||
483 | */ | ||
484 | tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; | ||
485 | } | ||
486 | 320 | ||
487 | /* | 321 | /* |
488 | * switch_to(x,yn) should switch tasks from x to y. | 322 | * switch_to(x,yn) should switch tasks from x to y. |
@@ -543,7 +377,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |||
543 | * used %fs or %gs (it does not today), or if the kernel is | 377 | * used %fs or %gs (it does not today), or if the kernel is |
544 | * running inside of a hypervisor layer. | 378 | * running inside of a hypervisor layer. |
545 | */ | 379 | */ |
546 | savesegment(gs, prev->gs); | 380 | lazy_save_gs(prev->gs); |
547 | 381 | ||
548 | /* | 382 | /* |
549 | * Load the per-thread Thread-Local Storage descriptor. | 383 | * Load the per-thread Thread-Local Storage descriptor. |
@@ -589,64 +423,44 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |||
589 | * Restore %gs if needed (which is common) | 423 | * Restore %gs if needed (which is common) |
590 | */ | 424 | */ |
591 | if (prev->gs | next->gs) | 425 | if (prev->gs | next->gs) |
592 | loadsegment(gs, next->gs); | 426 | lazy_load_gs(next->gs); |
593 | 427 | ||
594 | x86_write_percpu(current_task, next_p); | 428 | percpu_write(current_task, next_p); |
595 | 429 | ||
596 | return prev_p; | 430 | return prev_p; |
597 | } | 431 | } |
598 | 432 | ||
599 | asmlinkage int sys_fork(struct pt_regs regs) | 433 | int sys_clone(struct pt_regs *regs) |
600 | { | ||
601 | return do_fork(SIGCHLD, regs.sp, ®s, 0, NULL, NULL); | ||
602 | } | ||
603 | |||
604 | asmlinkage int sys_clone(struct pt_regs regs) | ||
605 | { | 434 | { |
606 | unsigned long clone_flags; | 435 | unsigned long clone_flags; |
607 | unsigned long newsp; | 436 | unsigned long newsp; |
608 | int __user *parent_tidptr, *child_tidptr; | 437 | int __user *parent_tidptr, *child_tidptr; |
609 | 438 | ||
610 | clone_flags = regs.bx; | 439 | clone_flags = regs->bx; |
611 | newsp = regs.cx; | 440 | newsp = regs->cx; |
612 | parent_tidptr = (int __user *)regs.dx; | 441 | parent_tidptr = (int __user *)regs->dx; |
613 | child_tidptr = (int __user *)regs.di; | 442 | child_tidptr = (int __user *)regs->di; |
614 | if (!newsp) | 443 | if (!newsp) |
615 | newsp = regs.sp; | 444 | newsp = regs->sp; |
616 | return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); | 445 | return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); |
617 | } | ||
618 | |||
619 | /* | ||
620 | * This is trivial, and on the face of it looks like it | ||
621 | * could equally well be done in user mode. | ||
622 | * | ||
623 | * Not so, for quite unobvious reasons - register pressure. | ||
624 | * In user mode vfork() cannot have a stack frame, and if | ||
625 | * done by calling the "clone()" system call directly, you | ||
626 | * do not have enough call-clobbered registers to hold all | ||
627 | * the information you need. | ||
628 | */ | ||
629 | asmlinkage int sys_vfork(struct pt_regs regs) | ||
630 | { | ||
631 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, ®s, 0, NULL, NULL); | ||
632 | } | 446 | } |
633 | 447 | ||
634 | /* | 448 | /* |
635 | * sys_execve() executes a new program. | 449 | * sys_execve() executes a new program. |
636 | */ | 450 | */ |
637 | asmlinkage int sys_execve(struct pt_regs regs) | 451 | int sys_execve(struct pt_regs *regs) |
638 | { | 452 | { |
639 | int error; | 453 | int error; |
640 | char *filename; | 454 | char *filename; |
641 | 455 | ||
642 | filename = getname((char __user *) regs.bx); | 456 | filename = getname((char __user *) regs->bx); |
643 | error = PTR_ERR(filename); | 457 | error = PTR_ERR(filename); |
644 | if (IS_ERR(filename)) | 458 | if (IS_ERR(filename)) |
645 | goto out; | 459 | goto out; |
646 | error = do_execve(filename, | 460 | error = do_execve(filename, |
647 | (char __user * __user *) regs.cx, | 461 | (char __user * __user *) regs->cx, |
648 | (char __user * __user *) regs.dx, | 462 | (char __user * __user *) regs->dx, |
649 | ®s); | 463 | regs); |
650 | if (error == 0) { | 464 | if (error == 0) { |
651 | /* Make sure we don't return using sysenter.. */ | 465 | /* Make sure we don't return using sysenter.. */ |
652 | set_thread_flag(TIF_IRET); | 466 | set_thread_flag(TIF_IRET); |