diff options
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/cpu/sh4/sq.c | 2 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh5/entry.S | 19 | ||||
-rw-r--r-- | arch/sh/kernel/entry-common.S | 16 | ||||
-rw-r--r-- | arch/sh/kernel/machine_kexec.c | 8 | ||||
-rw-r--r-- | arch/sh/kernel/module.c | 7 | ||||
-rw-r--r-- | arch/sh/kernel/ptrace_32.c | 157 | ||||
-rw-r--r-- | arch/sh/kernel/ptrace_64.c | 144 | ||||
-rw-r--r-- | arch/sh/kernel/setup.c | 20 | ||||
-rw-r--r-- | arch/sh/kernel/signal_32.c | 22 | ||||
-rw-r--r-- | arch/sh/kernel/signal_64.c | 166 |
10 files changed, 263 insertions, 298 deletions
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index dcdf959a3d4..8a8a993f55e 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -199,7 +199,7 @@ EXPORT_SYMBOL(sq_remap); /** * sq_unmap - Unmap a Store Queue allocation - * @map: Pre-allocated Store Queue mapping. + * @vaddr: Pre-allocated Store Queue mapping. * * Unmaps the store queue allocation @map that was previously created by * sq_remap(). Also frees up the pte that was previously inserted into diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S index ca08e7f26a3..04c7da96814 100644 --- a/arch/sh/kernel/cpu/sh5/entry.S +++ b/arch/sh/kernel/cpu/sh5/entry.S @@ -987,11 +987,11 @@ work_resched: work_notifysig: gettr tr1, LINK - movi do_signal, r6 + movi do_notify_resume, r6 ptabs r6, tr0 or SP, ZERO, r2 - or ZERO, ZERO, r3 - blink tr0, LINK /* Call do_signal(regs, 0), return here */ + or r7, ZERO, r3 + blink tr0, LINK /* Call do_notify_resume(regs, current_thread_info->flags), return here */ restore_all: /* Do prefetches */ @@ -1300,18 +1300,20 @@ syscall_allowed: getcon KCR0, r2 ld.l r2, TI_FLAGS, r4 - movi (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | _TIF_SYSCALL_AUDIT), r6 + movi _TIF_WORK_SYSCALL_MASK, r6 and r6, r4, r6 beq/l r6, ZERO, tr0 /* Trace it by calling syscall_trace before and after */ - movi syscall_trace, r4 + movi do_syscall_trace_enter, r4 or SP, ZERO, r2 - or ZERO, ZERO, r3 ptabs r4, tr0 blink tr0, LINK - /* Reload syscall number as r5 is trashed by syscall_trace */ + /* Save the retval */ + st.q SP, FRAME_R(2), r2 + + /* Reload syscall number as r5 is trashed by do_syscall_trace_enter */ ld.q SP, FRAME_S(FSYSCALL_ID), r5 andi r5, 0x1ff, r5 @@ -1343,9 +1345,8 @@ syscall_ret_trace: /* We get back here only if under trace */ st.q SP, FRAME_R(9), r2 /* Save return value */ - movi syscall_trace, LINK + movi do_syscall_trace_leave, LINK or SP, ZERO, r2 - movi 1, r3 ptabs LINK, tr0 blink tr0, LINK diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index 5e0dd193384..0bc17def55a 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S @@ -202,7 +202,7 @@ work_resched: syscall_exit_work: ! r0: current_thread_info->flags ! r8: current_thread_info - tst #_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | _TIF_SYSCALL_AUDIT, r0 + tst #_TIF_WORK_SYSCALL_MASK, r0 bt/s work_pending tst #_TIF_NEED_RESCHED, r0 #ifdef CONFIG_TRACE_IRQFLAGS @@ -211,10 +211,8 @@ syscall_exit_work: nop #endif sti - ! XXX setup arguments... mov r15, r4 - mov #1, r5 - mov.l 4f, r0 ! do_syscall_trace + mov.l 8f, r0 ! do_syscall_trace_leave jsr @r0 nop bra resume_userspace @@ -223,12 +221,11 @@ syscall_exit_work: .align 2 syscall_trace_entry: ! Yes it is traced. - ! XXX setup arguments... mov r15, r4 - mov #0, r5 - mov.l 4f, r11 ! Call do_syscall_trace which notifies + mov.l 7f, r11 ! Call do_syscall_trace_enter which notifies jsr @r11 ! superior (will chomp R[0-7]) nop + mov.l r0, @(OFF_R0,r15) ! Save return value ! Reload R0-R4 from kernel stack, where the ! parent may have modified them using ! ptrace(POKEUSR). (Note that R0-R2 are @@ -351,7 +348,7 @@ ENTRY(system_call) ! get_current_thread_info r8, r10 mov.l @(TI_FLAGS,r8), r8 - mov #(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT), r10 + mov #_TIF_WORK_SYSCALL_MASK, r10 tst r10, r8 bf syscall_trace_entry ! @@ -389,8 +386,9 @@ syscall_exit: #endif 2: .long NR_syscalls 3: .long sys_call_table -4: .long do_syscall_trace #ifdef CONFIG_TRACE_IRQFLAGS 5: .long trace_hardirqs_on 6: .long trace_hardirqs_off #endif +7: .long do_syscall_trace_enter +8: .long do_syscall_trace_leave diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c index ec1eadce4aa..4703dff174d 100644 --- a/arch/sh/kernel/machine_kexec.c +++ b/arch/sh/kernel/machine_kexec.c @@ -13,6 +13,7 @@ #include <linux/kexec.h> #include <linux/delay.h> #include <linux/reboot.h> +#include <linux/numa.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> #include <asm/mmu_context.h> @@ -104,3 +105,10 @@ void machine_kexec(struct kimage *image) (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg); } +void arch_crash_save_vmcoreinfo(void) +{ +#ifdef CONFIG_NUMA + VMCOREINFO_SYMBOL(node_data); + VMCOREINFO_LENGTH(node_data, MAX_NUMNODES); +#endif +} diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c index 5482e65375a..c43081039dd 100644 --- a/arch/sh/kernel/module.c +++ b/arch/sh/kernel/module.c @@ -27,6 +27,7 @@ #include <linux/moduleloader.h> #include <linux/elf.h> #include <linux/vmalloc.h> +#include <linux/bug.h> #include <linux/fs.h> #include <linux/string.h> #include <linux/kernel.h> @@ -36,7 +37,8 @@ void *module_alloc(unsigned long size) { if (size == 0) return NULL; - return vmalloc(size); + + return vmalloc_exec(size); } @@ -145,9 +147,10 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) { - return 0; + return module_bug_finalize(hdr, sechdrs, me); } void module_arch_cleanup(struct module *mod) { + module_bug_cleanup(mod); } diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 2bc72def5cf..035cb300d3d 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -20,6 +20,8 @@ #include <linux/signal.h> #include <linux/io.h> #include <linux/audit.h> +#include <linux/seccomp.h> +#include <linux/tracehook.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/system.h> @@ -57,7 +59,23 @@ static inline int put_stack_long(struct task_struct *task, int offset, return 0; } -static void ptrace_disable_singlestep(struct task_struct *child) +void user_enable_single_step(struct task_struct *child) +{ + struct pt_regs *regs = task_pt_regs(child); + long pc; + + pc = get_stack_long(child, (long)®s->pc); + + /* Next scheduling will set up UBC */ + if (child->thread.ubc_pc == 0) + ubc_usercnt += 1; + + child->thread.ubc_pc = pc; + + set_tsk_thread_flag(child, TIF_SINGLESTEP); +} + +void user_disable_single_step(struct task_struct *child) { clear_tsk_thread_flag(child, TIF_SINGLESTEP); @@ -81,7 +99,7 @@ static void ptrace_disable_singlestep(struct task_struct *child) */ void ptrace_disable(struct task_struct *child) { - ptrace_disable_singlestep(child); + user_disable_single_step(child); } long arch_ptrace(struct task_struct *child, long request, long addr, long data) @@ -90,12 +108,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) int ret; switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: - ret = generic_ptrace_peekdata(child, addr, data); - break; - /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp; @@ -125,12 +137,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } - /* when I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = generic_ptrace_pokedata(child, addr, data); - break; - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ret = -EIO; if ((addr & 3) || addr < 0 || @@ -151,67 +157,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } break; - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ - ret = -EIO; - if (!valid_signal(data)) - break; - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - - ptrace_disable_singlestep(child); - - child->exit_code = data; - wake_up_process(child); - ret = 0; - break; - } - -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: { - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - ptrace_disable_singlestep(child); - child->exit_code = SIGKILL; - wake_up_process(child); - break; - } - - case PTRACE_SINGLESTEP: { /* set the trap flag. */ - long pc; - struct pt_regs *regs = NULL; - - ret = -EIO; - if (!valid_signal(data)) - break; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - if ((child->ptrace & PT_DTRACE) == 0) { - /* Spurious delayed TF traps may occur */ - child->ptrace |= PT_DTRACE; - } - - pc = get_stack_long(child, (long)®s->pc); - - /* Next scheduling will set up UBC */ - if (child->thread.ubc_pc == 0) - ubc_usercnt += 1; - child->thread.ubc_pc = pc; - - set_tsk_thread_flag(child, TIF_SINGLESTEP); - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; - break; - } - #ifdef CONFIG_SH_DSP case PTRACE_GETDSPREGS: { unsigned long dp; @@ -272,39 +217,49 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return ret; } -asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) +static inline int audit_arch(void) { - struct task_struct *tsk = current; + int arch = EM_SH; - if (unlikely(current->audit_context) && entryexit) - audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]), - regs->regs[0]); +#ifdef CONFIG_CPU_LITTLE_ENDIAN + arch |= __AUDIT_ARCH_LE; +#endif - if (!test_thread_flag(TIF_SYSCALL_TRACE) && - !test_thread_flag(TIF_SINGLESTEP)) - goto out; - if (!(tsk->ptrace & PT_PTRACED)) - goto out; + return arch; +} - /* the 0x80 provides a way for the tracing parent to distinguish - between a syscall stop and SIGTRAP delivery */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) && - !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0)); +asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) +{ + long ret = 0; - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (tsk->exit_code) { - send_sig(tsk->exit_code, tsk, 1); - tsk->exit_code = 0; - } + secure_computing(regs->regs[0]); + + if (test_thread_flag(TIF_SYSCALL_TRACE) && + tracehook_report_syscall_entry(regs)) + /* + * Tracing decided this syscall should not happen. + * We'll return a bogus call number to get an ENOSYS + * error, but leave the original number in regs->regs[0]. + */ + ret = -1L; -out: - if (unlikely(current->audit_context) && !entryexit) - audit_syscall_entry(AUDIT_ARCH_SH, regs->regs[3], + if (unlikely(current->audit_context)) + audit_syscall_entry(audit_arch(), regs->regs[3], regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); + return ret ?: regs->regs[0]; +} + +asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) +{ + int step; + + if (unlikely(current->audit_context)) + audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]), + regs->regs[0]); + + step = test_thread_flag(TIF_SINGLESTEP); + if (step || test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(regs, step); } diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index d453c47dc52..5922edd416d 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c @@ -27,6 +27,8 @@ #include <linux/signal.h> #include <linux/syscalls.h> #include <linux/audit.h> +#include <linux/seccomp.h> +#include <linux/tracehook.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -120,18 +122,23 @@ put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data) return 0; } +void user_enable_single_step(struct task_struct *child) +{ + struct pt_regs *regs = child->thread.uregs; + + regs->sr |= SR_SSTEP; /* auto-resetting upon exception */ +} + +void user_disable_single_step(struct task_struct *child) +{ + regs->sr &= ~SR_SSTEP; +} long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int ret; switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: - ret = generic_ptrace_peekdata(child, addr, data); - break; - /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp; @@ -154,12 +161,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } - /* when I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = generic_ptrace_pokedata(child, addr, data); - break; - case PTRACE_POKEUSR: /* write the word at location addr in the USER area. We must disallow any changes to certain SR bits or u_fpvalid, since @@ -191,58 +192,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } break; - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ - ret = -EIO; - if (!valid_signal(data)) - break; - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - child->exit_code = data; - wake_up_process(child); - ret = 0; - break; - } - -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: { - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - child->exit_code = SIGKILL; - wake_up_process(child); - break; - } - - case PTRACE_SINGLESTEP: { /* set the trap flag. */ - struct pt_regs *regs; - - ret = -EIO; - if (!valid_signal(data)) - break; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - if ((child->ptrace & PT_DTRACE) == 0) { - /* Spurious delayed TF traps may occur */ - child->ptrace |= PT_DTRACE; - } - - regs = child->thread.uregs; - - regs->sr |= SR_SSTEP; /* auto-resetting upon exception */ - - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; - break; - } - default: ret = ptrace_request(child, request, addr, data); break; @@ -273,38 +222,51 @@ asmlinkage int sh64_ptrace(long request, long pid, long addr, long data) return sys_ptrace(request, pid, addr, data); } -asmlinkage void syscall_trace(struct pt_regs *regs, int entryexit) +static inline int audit_arch(void) { - struct task_struct *tsk = current; + int arch = EM_SH; - if (unlikely(current->audit_context) && entryexit) - audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]), - regs->regs[9]); +#ifdef CONFIG_64BIT + arch |= __AUDIT_ARCH_64BIT; +#endif +#ifdef CONFIG_CPU_LITTLE_ENDIAN + arch |= __AUDIT_ARCH_LE; +#endif - if (!test_thread_flag(TIF_SYSCALL_TRACE) && - !test_thread_flag(TIF_SINGLESTEP)) - goto out; - if (!(tsk->ptrace & PT_PTRACED)) - goto out; - - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) && - !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0)); - - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (tsk->exit_code) { - send_sig(tsk->exit_code, tsk, 1); - tsk->exit_code = 0; - } + return arch; +} -out: - if (unlikely(current->audit_context) && !entryexit) - audit_syscall_entry(AUDIT_ARCH_SH, regs->regs[1], +asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs) +{ + long long ret = 0; + + secure_computing(regs->regs[9]); + + if (test_thread_flag(TIF_SYSCALL_TRACE) && + tracehook_report_syscall_entry(regs)) + /* + * Tracing decided this syscall should not happen. + * We'll return a bogus call number to get an ENOSYS + * error, but leave the original number in regs->regs[0]. + */ + ret = -1LL; + + if (unlikely(current->audit_context)) + audit_syscall_entry(audit_arch(), regs->regs[1], regs->regs[2], regs->regs[3], regs->regs[4], regs->regs[5]); + + return ret ?: regs->regs[9]; +} + +asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) +{ + if (unlikely(current->audit_context)) + audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]), + regs->regs[9]); + + if (test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(regs, 0); } /* Called with interrupts disabled */ @@ -338,5 +300,5 @@ asmlinkage void do_software_break_point(unsigned long long vec, */ void ptrace_disable(struct task_struct *child) { - /* nothing to do.. */ + user_disable_single_step(child); } diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 6339d0c9571..a35207655e7 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -25,6 +25,7 @@ #include <linux/smp.h> #include <linux/err.h> #include <linux/debugfs.h> +#include <linux/crash_dump.h> #include <asm/uaccess.h> #include <asm/io.h> #include <asm/page.h> @@ -286,6 +287,25 @@ static void __init setup_memory(void) extern void __init setup_memory(void); #endif +/* + * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by + * is_kdump_kernel() to determine if we are booting after a panic. Hence + * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE. + */ +#ifdef CONFIG_CRASH_DUMP +/* elfcorehdr= specifies the location of elf core header + * stored by the crashed kernel. + */ +static int __init parse_elfcorehdr(char *arg) +{ + if (!arg) + return -EINVAL; + elfcorehdr_addr = memparse(arg, &arg); + return 0; +} +early_param("elfcorehdr", parse_elfcorehdr); +#endif + void __init setup_arch(char **cmdline_p) { enable_mmu(); diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 4bbbde895a5..51689d29ad4 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -24,6 +24,7 @@ #include <linux/binfmts.h> #include <linux/freezer.h> #include <linux/io.h> +#include <linux/tracehook.h> #include <asm/system.h> #include <asm/ucontext.h> #include <asm/uaccess.h> @@ -507,14 +508,13 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, switch (regs->regs[0]) { case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND: + no_system_call_restart: regs->regs[0] = -EINTR; break; case -ERESTARTSYS: - if (!(ka->sa.sa_flags & SA_RESTART)) { - regs->regs[0] = -EINTR; - break; - } + if (!(ka->sa.sa_flags & SA_RESTART)) + goto no_system_call_restart; /* fallthrough */ case -ERESTARTNOINTR: regs->regs[0] = save_r0; @@ -589,12 +589,15 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) * clear the TIF_RESTORE_SIGMASK flag */ if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signr, &info, &ka, regs, + test_thread_flag(TIF_SINGLESTEP)); } return; } - no_signal: +no_signal: /* Did we come from a system call? */ if (regs->tra >= 0) { /* Restart the system call - no handlers present */ @@ -618,9 +621,14 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) } asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, - __u32 thread_info_flags) + unsigned long thread_info_flags) { /* deal with pending signal delivery */ - if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) + if (thread_info_flags & _TIF_SIGPENDING) do_signal(regs, save_r0); + + if (thread_info_flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } } diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 552eb810cd8..1d62dfef77f 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c @@ -22,6 +22,7 @@ #include <linux/ptrace.h> #include <linux/unistd.h> #include <linux/stddef.h> +#include <linux/tracehook.h> #include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -42,7 +43,84 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + * + * Note that we go through the signals twice: once to check the signals that + * the kernel can handle, and then we build all the user-level signal handling + * stack-frames in one go after that. + */ +static int do_signal(struct pt_regs *regs, sigset_t *oldset) +{ + siginfo_t info; + int signr; + struct k_sigaction ka; + + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 1; + + if (try_to_freeze()) + goto no_signal; + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else if (!oldset) + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, &ka, regs, 0); + + if (signr > 0) { + /* Whee! Actually deliver the signal. */ + handle_signal(signr, &info, &ka, oldset, regs); + + /* + * If a signal was successfully delivered, the saved sigmask + * is in its frame, and we can clear the TIF_RESTORE_SIGMASK + * flag. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signr, &info, &ka, regs, 0); + return 1; + } + +no_signal: + /* Did we come from a system call? */ + if (regs->syscall_nr >= 0) { + /* Restart the system call - no handlers present */ + switch (regs->regs[REG_RET]) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + /* Decode Syscall # */ + regs->regs[REG_RET] = regs->syscall_nr; + regs->pc -= 4; + break; + + case -ERESTART_RESTARTBLOCK: + regs->regs[REG_RET] = __NR_restart_syscall; + regs->pc -= 4; + break; + } + } + + /* No signal to deliver -- put the saved sigmask back */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + + return 0; +} /* * Atomically swap in the new signal mask, and wait for a signal. @@ -643,14 +721,13 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, switch (regs->regs[REG_RET]) { case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND: + no_system_call_restart: regs->regs[REG_RET] = -EINTR; break; case -ERESTARTSYS: - if (!(ka->sa.sa_flags & SA_RESTART)) { - regs->regs[REG_RET] = -EINTR; - break; - } + if (!(ka->sa.sa_flags & SA_RESTART)) + goto no_system_call_restart; /* fallthrough */ case -ERESTARTNOINTR: /* Decode syscall # */ @@ -673,80 +750,13 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, spin_unlock_irq(¤t->sighand->siglock); } -/* - * Note that 'init' is a special process: it doesn't get signals it doesn't - * want to handle. Thus you cannot kill init even with a SIGKILL even by - * mistake. - * - * Note that we go through the signals twice: once to check the signals that - * the kernel can handle, and then we build all the user-level signal handling - * stack-frames in one go after that. - */ -int do_signal(struct pt_regs *regs, sigset_t *oldset) +asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) { - siginfo_t info; - int signr; - struct k_sigaction ka; - - /* - * We want the common case to go fast, which - * is why we may in certain cases get here from - * kernel mode. Just return without doing anything - * if so. - */ - if (!user_mode(regs)) - return 1; - - if (try_to_freeze()) - goto no_signal; - - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - oldset = ¤t->saved_sigmask; - else if (!oldset) - oldset = ¤t->blocked; - - signr = get_signal_to_deliver(&info, &ka, regs, 0); - - if (signr > 0) { - /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, oldset, regs); + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(regs, 0); - /* - * If a signal was successfully delivered, the saved sigmask - * is in its frame, and we can clear the TIF_RESTORE_SIGMASK - * flag. - */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - clear_thread_flag(TIF_RESTORE_SIGMASK); - - return 1; + if (thread_info_flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); } - -no_signal: - /* Did we come from a system call? */ - if (regs->syscall_nr >= 0) { - /* Restart the system call - no handlers present */ - switch (regs->regs[REG_RET]) { - case -ERESTARTNOHAND: - case -ERESTARTSYS: - case -ERESTARTNOINTR: - /* Decode Syscall # */ - regs->regs[REG_RET] = regs->syscall_nr; - regs->pc -= 4; - break; - - case -ERESTART_RESTARTBLOCK: - regs->regs[REG_RET] = __NR_restart_syscall; - regs->pc -= 4; - break; - } - } - - /* No signal to deliver -- put the saved sigmask back */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); - sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); - } - - return 0; } |