aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel/process.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/tile/kernel/process.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'arch/tile/kernel/process.c')
-rw-r--r--arch/tile/kernel/process.c110
1 files changed, 86 insertions, 24 deletions
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 84c29111756c..9c45d8bbdf57 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -25,10 +25,13 @@
25#include <linux/hardirq.h> 25#include <linux/hardirq.h>
26#include <linux/syscalls.h> 26#include <linux/syscalls.h>
27#include <linux/kernel.h> 27#include <linux/kernel.h>
28#include <linux/tracehook.h>
29#include <linux/signal.h>
28#include <asm/system.h> 30#include <asm/system.h>
29#include <asm/stack.h> 31#include <asm/stack.h>
30#include <asm/homecache.h> 32#include <asm/homecache.h>
31#include <asm/syscalls.h> 33#include <asm/syscalls.h>
34#include <asm/traps.h>
32#ifdef CONFIG_HARDWALL 35#ifdef CONFIG_HARDWALL
33#include <asm/hardwall.h> 36#include <asm/hardwall.h>
34#endif 37#endif
@@ -109,7 +112,7 @@ void cpu_idle(void)
109 } 112 }
110} 113}
111 114
112struct thread_info *alloc_thread_info(struct task_struct *task) 115struct thread_info *alloc_thread_info_node(struct task_struct *task, int node)
113{ 116{
114 struct page *page; 117 struct page *page;
115 gfp_t flags = GFP_KERNEL; 118 gfp_t flags = GFP_KERNEL;
@@ -118,7 +121,7 @@ struct thread_info *alloc_thread_info(struct task_struct *task)
118 flags |= __GFP_ZERO; 121 flags |= __GFP_ZERO;
119#endif 122#endif
120 123
121 page = alloc_pages(flags, THREAD_SIZE_ORDER); 124 page = alloc_pages_node(node, flags, THREAD_SIZE_ORDER);
122 if (!page) 125 if (!page)
123 return NULL; 126 return NULL;
124 127
@@ -165,7 +168,7 @@ void free_thread_info(struct thread_info *info)
165 kfree(step_state); 168 kfree(step_state);
166 } 169 }
167 170
168 free_page((unsigned long)info); 171 free_pages((unsigned long)info, THREAD_SIZE_ORDER);
169} 172}
170 173
171static void save_arch_state(struct thread_struct *t); 174static void save_arch_state(struct thread_struct *t);
@@ -212,11 +215,19 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
212 childregs->sp = sp; /* override with new user stack pointer */ 215 childregs->sp = sp; /* override with new user stack pointer */
213 216
214 /* 217 /*
218 * If CLONE_SETTLS is set, set "tp" in the new task to "r4",
219 * which is passed in as arg #5 to sys_clone().
220 */
221 if (clone_flags & CLONE_SETTLS)
222 childregs->tp = regs->regs[4];
223
224 /*
215 * Copy the callee-saved registers from the passed pt_regs struct 225 * Copy the callee-saved registers from the passed pt_regs struct
216 * into the context-switch callee-saved registers area. 226 * into the context-switch callee-saved registers area.
217 * We have to restore the callee-saved registers since we may 227 * This way when we start the interrupt-return sequence, the
218 * be cloning a userspace task with userspace register state, 228 * callee-save registers will be correctly in registers, which
219 * and we won't be unwinding the same kernel frames to restore them. 229 * is how we assume the compiler leaves them as we start doing
230 * 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. 231 * Zero out the C ABI save area to mark the top of the stack.
221 */ 232 */
222 ksp = (unsigned long) childregs; 233 ksp = (unsigned long) childregs;
@@ -304,15 +315,25 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
304/* Allow user processes to access the DMA SPRs */ 315/* Allow user processes to access the DMA SPRs */
305void grant_dma_mpls(void) 316void grant_dma_mpls(void)
306{ 317{
318#if CONFIG_KERNEL_PL == 2
319 __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1);
320 __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1);
321#else
307 __insn_mtspr(SPR_MPL_DMA_CPL_SET_0, 1); 322 __insn_mtspr(SPR_MPL_DMA_CPL_SET_0, 1);
308 __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_0, 1); 323 __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_0, 1);
324#endif
309} 325}
310 326
311/* Forbid user processes from accessing the DMA SPRs */ 327/* Forbid user processes from accessing the DMA SPRs */
312void restrict_dma_mpls(void) 328void restrict_dma_mpls(void)
313{ 329{
330#if CONFIG_KERNEL_PL == 2
331 __insn_mtspr(SPR_MPL_DMA_CPL_SET_2, 1);
332 __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_2, 1);
333#else
314 __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1); 334 __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1);
315 __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1); 335 __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1);
336#endif
316} 337}
317 338
318/* Pause the DMA engine, then save off its state registers. */ 339/* Pause the DMA engine, then save off its state registers. */
@@ -523,19 +544,60 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
523 * Switch kernel SP, PC, and callee-saved registers. 544 * Switch kernel SP, PC, and callee-saved registers.
524 * In the context of the new task, return the old task pointer 545 * In the context of the new task, return the old task pointer
525 * (i.e. the task that actually called __switch_to). 546 * (i.e. the task that actually called __switch_to).
526 * Pass the value to use for SYSTEM_SAVE_1_0 when we reset our sp. 547 * Pass the value to use for SYSTEM_SAVE_K_0 when we reset our sp.
527 */ 548 */
528 return __switch_to(prev, next, next_current_ksp0(next)); 549 return __switch_to(prev, next, next_current_ksp0(next));
529} 550}
530 551
531long _sys_fork(struct pt_regs *regs) 552/*
553 * This routine is called on return from interrupt if any of the
554 * TIF_WORK_MASK flags are set in thread_info->flags. It is
555 * entered with interrupts disabled so we don't miss an event
556 * that modified the thread_info flags. If any flag is set, we
557 * handle it and return, and the calling assembly code will
558 * re-disable interrupts, reload the thread flags, and call back
559 * if more flags need to be handled.
560 *
561 * We return whether we need to check the thread_info flags again
562 * or not. Note that we don't clear TIF_SINGLESTEP here, so it's
563 * important that it be tested last, and then claim that we don't
564 * need to recheck the flags.
565 */
566int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
532{ 567{
533 return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); 568 if (thread_info_flags & _TIF_NEED_RESCHED) {
569 schedule();
570 return 1;
571 }
572#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
573 if (thread_info_flags & _TIF_ASYNC_TLB) {
574 do_async_page_fault(regs);
575 return 1;
576 }
577#endif
578 if (thread_info_flags & _TIF_SIGPENDING) {
579 do_signal(regs);
580 return 1;
581 }
582 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
583 clear_thread_flag(TIF_NOTIFY_RESUME);
584 tracehook_notify_resume(regs);
585 if (current->replacement_session_keyring)
586 key_replace_session_keyring();
587 return 1;
588 }
589 if (thread_info_flags & _TIF_SINGLESTEP) {
590 if ((regs->ex1 & SPR_EX_CONTEXT_1_1__PL_MASK) == 0)
591 single_step_once(regs);
592 return 0;
593 }
594 panic("work_pending: bad flags %#x\n", thread_info_flags);
534} 595}
535 596
536long _sys_clone(unsigned long clone_flags, unsigned long newsp, 597/* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */
537 void __user *parent_tidptr, void __user *child_tidptr, 598SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
538 struct pt_regs *regs) 599 void __user *, parent_tidptr, void __user *, child_tidptr,
600 struct pt_regs *, regs)
539{ 601{
540 if (!newsp) 602 if (!newsp)
541 newsp = regs->sp; 603 newsp = regs->sp;
@@ -543,18 +605,13 @@ long _sys_clone(unsigned long clone_flags, unsigned long newsp,
543 parent_tidptr, child_tidptr); 605 parent_tidptr, child_tidptr);
544} 606}
545 607
546long _sys_vfork(struct pt_regs *regs)
547{
548 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp,
549 regs, 0, NULL, NULL);
550}
551
552/* 608/*
553 * sys_execve() executes a new program. 609 * sys_execve() executes a new program.
554 */ 610 */
555long _sys_execve(const char __user *path, 611SYSCALL_DEFINE4(execve, const char __user *, path,
556 const char __user *const __user *argv, 612 const char __user *const __user *, argv,
557 const char __user *const __user *envp, struct pt_regs *regs) 613 const char __user *const __user *, envp,
614 struct pt_regs *, regs)
558{ 615{
559 long error; 616 long error;
560 char *filename; 617 char *filename;
@@ -565,14 +622,17 @@ long _sys_execve(const char __user *path,
565 goto out; 622 goto out;
566 error = do_execve(filename, argv, envp, regs); 623 error = do_execve(filename, argv, envp, regs);
567 putname(filename); 624 putname(filename);
625 if (error == 0)
626 single_step_execve();
568out: 627out:
569 return error; 628 return error;
570} 629}
571 630
572#ifdef CONFIG_COMPAT 631#ifdef CONFIG_COMPAT
573long _compat_sys_execve(const char __user *path, 632long compat_sys_execve(const char __user *path,
574 const compat_uptr_t __user *argv, 633 compat_uptr_t __user *argv,
575 const compat_uptr_t __user *envp, struct pt_regs *regs) 634 compat_uptr_t __user *envp,
635 struct pt_regs *regs)
576{ 636{
577 long error; 637 long error;
578 char *filename; 638 char *filename;
@@ -583,6 +643,8 @@ long _compat_sys_execve(const char __user *path,
583 goto out; 643 goto out;
584 error = compat_do_execve(filename, argv, envp, regs); 644 error = compat_do_execve(filename, argv, envp, regs);
585 putname(filename); 645 putname(filename);
646 if (error == 0)
647 single_step_execve();
586out: 648out:
587 return error; 649 return error;
588} 650}