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