diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/tile/kernel/process.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (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.c | 110 |
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 | ||
112 | struct thread_info *alloc_thread_info(struct task_struct *task) | 115 | struct 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 | ||
171 | static void save_arch_state(struct thread_struct *t); | 174 | static 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 */ |
305 | void grant_dma_mpls(void) | 316 | void 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 */ |
312 | void restrict_dma_mpls(void) | 328 | void 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 | ||
531 | long _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 | */ | ||
566 | int 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 | ||
536 | long _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, | 598 | SYSCALL_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 | ||
546 | long _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 | */ |
555 | long _sys_execve(const char __user *path, | 611 | SYSCALL_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(); | ||
568 | out: | 627 | out: |
569 | return error; | 628 | return error; |
570 | } | 629 | } |
571 | 630 | ||
572 | #ifdef CONFIG_COMPAT | 631 | #ifdef CONFIG_COMPAT |
573 | long _compat_sys_execve(const char __user *path, | 632 | long 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(); | ||
586 | out: | 648 | out: |
587 | return error; | 649 | return error; |
588 | } | 650 | } |