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); |
