diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2010-12-30 00:20:30 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2010-12-30 00:21:47 -0500 |
commit | d392da5207352f09030e95d9ea335a4225667ec0 (patch) | |
tree | 7d6cd1932afcad0a5619a5c504a6d93ca318187c /arch/tile/kernel/process.c | |
parent | e39d5ef678045d61812c1401f04fe8edb14d6359 (diff) | |
parent | 387c31c7e5c9805b0aef8833d1731a5fe7bdea14 (diff) |
Merge v2.6.37-rc8 into powerpc/next
Diffstat (limited to 'arch/tile/kernel/process.c')
-rw-r--r-- | arch/tile/kernel/process.c | 81 |
1 files changed, 51 insertions, 30 deletions
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index ed590ad0acdc..e90eb53173b0 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c | |||
@@ -212,11 +212,19 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
212 | childregs->sp = sp; /* override with new user stack pointer */ | 212 | childregs->sp = sp; /* override with new user stack pointer */ |
213 | 213 | ||
214 | /* | 214 | /* |
215 | * If CLONE_SETTLS is set, set "tp" in the new task to "r4", | ||
216 | * which is passed in as arg #5 to sys_clone(). | ||
217 | */ | ||
218 | if (clone_flags & CLONE_SETTLS) | ||
219 | childregs->tp = regs->regs[4]; | ||
220 | |||
221 | /* | ||
215 | * Copy the callee-saved registers from the passed pt_regs struct | 222 | * Copy the callee-saved registers from the passed pt_regs struct |
216 | * into the context-switch callee-saved registers area. | 223 | * into the context-switch callee-saved registers area. |
217 | * We have to restore the callee-saved registers since we may | 224 | * This way when we start the interrupt-return sequence, the |
218 | * be cloning a userspace task with userspace register state, | 225 | * callee-save registers will be correctly in registers, which |
219 | * and we won't be unwinding the same kernel frames to restore them. | 226 | * is how we assume the compiler leaves them as we start doing |
227 | * the normal return-from-interrupt path after calling C code. | ||
220 | * Zero out the C ABI save area to mark the top of the stack. | 228 | * Zero out the C ABI save area to mark the top of the stack. |
221 | */ | 229 | */ |
222 | ksp = (unsigned long) childregs; | 230 | ksp = (unsigned long) childregs; |
@@ -304,15 +312,25 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) | |||
304 | /* Allow user processes to access the DMA SPRs */ | 312 | /* Allow user processes to access the DMA SPRs */ |
305 | void grant_dma_mpls(void) | 313 | void grant_dma_mpls(void) |
306 | { | 314 | { |
315 | #if CONFIG_KERNEL_PL == 2 | ||
316 | __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1); | ||
317 | __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1); | ||
318 | #else | ||
307 | __insn_mtspr(SPR_MPL_DMA_CPL_SET_0, 1); | 319 | __insn_mtspr(SPR_MPL_DMA_CPL_SET_0, 1); |
308 | __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_0, 1); | 320 | __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_0, 1); |
321 | #endif | ||
309 | } | 322 | } |
310 | 323 | ||
311 | /* Forbid user processes from accessing the DMA SPRs */ | 324 | /* Forbid user processes from accessing the DMA SPRs */ |
312 | void restrict_dma_mpls(void) | 325 | void restrict_dma_mpls(void) |
313 | { | 326 | { |
327 | #if CONFIG_KERNEL_PL == 2 | ||
328 | __insn_mtspr(SPR_MPL_DMA_CPL_SET_2, 1); | ||
329 | __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_2, 1); | ||
330 | #else | ||
314 | __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1); | 331 | __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1); |
315 | __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1); | 332 | __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1); |
333 | #endif | ||
316 | } | 334 | } |
317 | 335 | ||
318 | /* Pause the DMA engine, then save off its state registers. */ | 336 | /* Pause the DMA engine, then save off its state registers. */ |
@@ -408,6 +426,15 @@ static void save_arch_state(struct thread_struct *t) | |||
408 | #if CHIP_HAS_PROC_STATUS_SPR() | 426 | #if CHIP_HAS_PROC_STATUS_SPR() |
409 | t->proc_status = __insn_mfspr(SPR_PROC_STATUS); | 427 | t->proc_status = __insn_mfspr(SPR_PROC_STATUS); |
410 | #endif | 428 | #endif |
429 | #if !CHIP_HAS_FIXED_INTVEC_BASE() | ||
430 | t->interrupt_vector_base = __insn_mfspr(SPR_INTERRUPT_VECTOR_BASE_0); | ||
431 | #endif | ||
432 | #if CHIP_HAS_TILE_RTF_HWM() | ||
433 | t->tile_rtf_hwm = __insn_mfspr(SPR_TILE_RTF_HWM); | ||
434 | #endif | ||
435 | #if CHIP_HAS_DSTREAM_PF() | ||
436 | t->dstream_pf = __insn_mfspr(SPR_DSTREAM_PF); | ||
437 | #endif | ||
411 | } | 438 | } |
412 | 439 | ||
413 | static void restore_arch_state(const struct thread_struct *t) | 440 | static void restore_arch_state(const struct thread_struct *t) |
@@ -428,14 +455,14 @@ static void restore_arch_state(const struct thread_struct *t) | |||
428 | #if CHIP_HAS_PROC_STATUS_SPR() | 455 | #if CHIP_HAS_PROC_STATUS_SPR() |
429 | __insn_mtspr(SPR_PROC_STATUS, t->proc_status); | 456 | __insn_mtspr(SPR_PROC_STATUS, t->proc_status); |
430 | #endif | 457 | #endif |
458 | #if !CHIP_HAS_FIXED_INTVEC_BASE() | ||
459 | __insn_mtspr(SPR_INTERRUPT_VECTOR_BASE_0, t->interrupt_vector_base); | ||
460 | #endif | ||
431 | #if CHIP_HAS_TILE_RTF_HWM() | 461 | #if CHIP_HAS_TILE_RTF_HWM() |
432 | /* | 462 | __insn_mtspr(SPR_TILE_RTF_HWM, t->tile_rtf_hwm); |
433 | * Clear this whenever we switch back to a process in case | 463 | #endif |
434 | * the previous process was monkeying with it. Even if enabled | 464 | #if CHIP_HAS_DSTREAM_PF() |
435 | * in CBOX_MSR1 via TILE_RTF_HWM_MIN, it's still just a | 465 | __insn_mtspr(SPR_DSTREAM_PF, t->dstream_pf); |
436 | * performance hint, so isn't worth a full save/restore. | ||
437 | */ | ||
438 | __insn_mtspr(SPR_TILE_RTF_HWM, 0); | ||
439 | #endif | 466 | #endif |
440 | } | 467 | } |
441 | 468 | ||
@@ -514,19 +541,15 @@ struct task_struct *__sched _switch_to(struct task_struct *prev, | |||
514 | * Switch kernel SP, PC, and callee-saved registers. | 541 | * Switch kernel SP, PC, and callee-saved registers. |
515 | * In the context of the new task, return the old task pointer | 542 | * In the context of the new task, return the old task pointer |
516 | * (i.e. the task that actually called __switch_to). | 543 | * (i.e. the task that actually called __switch_to). |
517 | * Pass the value to use for SYSTEM_SAVE_1_0 when we reset our sp. | 544 | * Pass the value to use for SYSTEM_SAVE_K_0 when we reset our sp. |
518 | */ | 545 | */ |
519 | return __switch_to(prev, next, next_current_ksp0(next)); | 546 | return __switch_to(prev, next, next_current_ksp0(next)); |
520 | } | 547 | } |
521 | 548 | ||
522 | long _sys_fork(struct pt_regs *regs) | 549 | /* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */ |
523 | { | 550 | SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, |
524 | return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); | 551 | void __user *, parent_tidptr, void __user *, child_tidptr, |
525 | } | 552 | struct pt_regs *, regs) |
526 | |||
527 | long _sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
528 | void __user *parent_tidptr, void __user *child_tidptr, | ||
529 | struct pt_regs *regs) | ||
530 | { | 553 | { |
531 | if (!newsp) | 554 | if (!newsp) |
532 | newsp = regs->sp; | 555 | newsp = regs->sp; |
@@ -534,17 +557,13 @@ long _sys_clone(unsigned long clone_flags, unsigned long newsp, | |||
534 | parent_tidptr, child_tidptr); | 557 | parent_tidptr, child_tidptr); |
535 | } | 558 | } |
536 | 559 | ||
537 | long _sys_vfork(struct pt_regs *regs) | ||
538 | { | ||
539 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, | ||
540 | regs, 0, NULL, NULL); | ||
541 | } | ||
542 | |||
543 | /* | 560 | /* |
544 | * sys_execve() executes a new program. | 561 | * sys_execve() executes a new program. |
545 | */ | 562 | */ |
546 | long _sys_execve(char __user *path, char __user *__user *argv, | 563 | SYSCALL_DEFINE4(execve, const char __user *, path, |
547 | char __user *__user *envp, struct pt_regs *regs) | 564 | const char __user *const __user *, argv, |
565 | const char __user *const __user *, envp, | ||
566 | struct pt_regs *, regs) | ||
548 | { | 567 | { |
549 | long error; | 568 | long error; |
550 | char *filename; | 569 | char *filename; |
@@ -560,8 +579,10 @@ out: | |||
560 | } | 579 | } |
561 | 580 | ||
562 | #ifdef CONFIG_COMPAT | 581 | #ifdef CONFIG_COMPAT |
563 | long _compat_sys_execve(char __user *path, compat_uptr_t __user *argv, | 582 | long compat_sys_execve(const char __user *path, |
564 | compat_uptr_t __user *envp, struct pt_regs *regs) | 583 | const compat_uptr_t __user *argv, |
584 | const compat_uptr_t __user *envp, | ||
585 | struct pt_regs *regs) | ||
565 | { | 586 | { |
566 | long error; | 587 | long error; |
567 | char *filename; | 588 | char *filename; |
@@ -656,7 +677,7 @@ void show_regs(struct pt_regs *regs) | |||
656 | regs->regs[51], regs->regs[52], regs->tp); | 677 | regs->regs[51], regs->regs[52], regs->tp); |
657 | pr_err(" sp : "REGFMT" lr : "REGFMT"\n", regs->sp, regs->lr); | 678 | pr_err(" sp : "REGFMT" lr : "REGFMT"\n", regs->sp, regs->lr); |
658 | #else | 679 | #else |
659 | for (i = 0; i < 52; i += 3) | 680 | for (i = 0; i < 52; i += 4) |
660 | pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT | 681 | pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT |
661 | " r%-2d: "REGFMT" r%-2d: "REGFMT"\n", | 682 | " r%-2d: "REGFMT" r%-2d: "REGFMT"\n", |
662 | i, regs->regs[i], i+1, regs->regs[i+1], | 683 | i, regs->regs[i], i+1, regs->regs[i+1], |