cregit-Linux how code gets into the kernel

Release 4.14 arch/microblaze/kernel/signal.c

/*
 * Signal handling
 *
 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
 * Copyright (C) 2008-2009 PetaLogix
 * Copyright (C) 2003,2004 John Williams <jwilliams@itee.uq.edu.au>
 * Copyright (C) 2001 NEC Corporation
 * Copyright (C) 2001 Miles Bader <miles@gnu.org>
 * Copyright (C) 1999,2000 Niibe Yutaka & Kaz Kojima
 * Copyright (C) 1991,1992 Linus Torvalds
 *
 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
 *
 * This file was was derived from the sh version, arch/sh/kernel/signal.c
 *
 * This file is subject to the terms and conditions of the GNU General
 * Public License. See the file COPYING in the main directory of this
 * archive for more details.
 */

#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/personality.h>
#include <linux/percpu.h>
#include <linux/linkage.h>
#include <linux/tracehook.h>
#include <asm/entry.h>
#include <asm/ucontext.h>
#include <linux/uaccess.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <linux/syscalls.h>
#include <asm/cacheflush.h>
#include <asm/syscalls.h>

/*
 * Do a signal return; undo the signal stack.
 */

struct sigframe {
	
struct sigcontext sc;
	
unsigned long extramask[_NSIG_WORDS-1];
	
unsigned long tramp[2];	/* signal trampoline */
};


struct rt_sigframe {
	
struct siginfo info;
	
struct ucontext uc;
	
unsigned long tramp[2];	/* signal trampoline */
};


static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *rval_p) { unsigned int err = 0; #define COPY(x) {err |= __get_user(regs->x, &sc->regs.x); } COPY(r0); COPY(r1); COPY(r2); COPY(r3); COPY(r4); COPY(r5); COPY(r6); COPY(r7); COPY(r8); COPY(r9); COPY(r10); COPY(r11); COPY(r12); COPY(r13); COPY(r14); COPY(r15); COPY(r16); COPY(r17); COPY(r18); COPY(r19); COPY(r20); COPY(r21); COPY(r22); COPY(r23); COPY(r24); COPY(r25); COPY(r26); COPY(r27); COPY(r28); COPY(r29); COPY(r30); COPY(r31); COPY(pc); COPY(ear); COPY(esr); COPY(fsr); #undef COPY *rval_p = regs->r3; return err; }

Contributors

PersonTokensPropCommitsCommitProp
Michal Simek16371.81%133.33%
Arnd Bergmann6428.19%266.67%
Total227100.00%3100.00%


asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(regs->r1); sigset_t set; int rval; /* Always make any pending restarted system calls return -EINTR */ current->restart_block.fn = do_no_restart_syscall; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval)) goto badframe; if (restore_altstack(&frame->uc.uc_stack)) goto badframe; return rval; badframe: force_sig(SIGSEGV, current); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michal Simek12487.32%225.00%
Al Viro96.34%225.00%
Arnd Bergmann74.93%225.00%
Matt Fleming10.70%112.50%
Andrew Lutomirski10.70%112.50%
Total142100.00%8100.00%

/* * Set up a signal frame. */
static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask) { int err = 0; #define COPY(x) {err |= __put_user(regs->x, &sc->regs.x); } COPY(r0); COPY(r1); COPY(r2); COPY(r3); COPY(r4); COPY(r5); COPY(r6); COPY(r7); COPY(r8); COPY(r9); COPY(r10); COPY(r11); COPY(r12); COPY(r13); COPY(r14); COPY(r15); COPY(r16); COPY(r17); COPY(r18); COPY(r19); COPY(r20); COPY(r21); COPY(r22); COPY(r23); COPY(r24); COPY(r25); COPY(r26); COPY(r27); COPY(r28); COPY(r29); COPY(r30); COPY(r31); COPY(pc); COPY(ear); COPY(esr); COPY(fsr); #undef COPY err |= __put_user(mask, &sc->oldmask); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Michal Simek23099.57%150.00%
Arnd Bergmann10.43%150.00%
Total231100.00%2100.00%

/* * Determine which stack to use.. */
static inline void __user * get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size) { /* Default to using normal stack */ unsigned long sp = sigsp(regs->r1, ksig); return (void __user *)((sp - frame_size) & -8UL); }

Contributors

PersonTokensPropCommitsCommitProp
Michal Simek4483.02%133.33%
Richard Weinberger713.21%133.33%
Arnd Bergmann23.77%133.33%
Total53100.00%3100.00%


static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { struct rt_sigframe __user *frame; int err = 0, sig = ksig->sig; unsigned long address = 0; #ifdef CONFIG_MMU pmd_t *pmdp; pte_t *ptep; #endif frame = get_sigframe(ksig, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) return -EFAULT; if (ksig->ka.sa.sa_flags & SA_SIGINFO) err |= copy_siginfo_to_user(&frame->info, &ksig->info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(NULL, &frame->uc.uc_link); err |= __save_altstack(&frame->uc.uc_stack, regs->r1); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Set up to return from userspace. If provided, use a stub already in userspace. */ /* minus 8 is offset to cater for "rtsd r15,8" */ /* addi r12, r0, __NR_sigreturn */ err |= __put_user(0x31800000 | __NR_rt_sigreturn , frame->tramp + 0); /* brki r14, 0x8 */ err |= __put_user(0xb9cc0008, frame->tramp + 1); /* Return from sighandler will jump to the tramp. Negative 8 offset because return is rtsd r15, 8 */ regs->r15 = ((unsigned long)frame->tramp)-8; address = ((unsigned long)frame->tramp); #ifdef CONFIG_MMU pmdp = pmd_offset(pud_offset( pgd_offset(current->mm, address), address), address); preempt_disable(); ptep = pte_offset_map(pmdp, address); if (pte_present(*ptep)) { address = (unsigned long) page_address(pte_page(*ptep)); /* MS: I need add offset in page */ address += ((unsigned long)frame->tramp) & ~PAGE_MASK; /* MS address is virtual */ address = __virt_to_phys(address); invalidate_icache_range(address, address + 8); flush_dcache_range(address, address + 8); } pte_unmap(ptep); preempt_enable(); #else flush_icache_range(address, address + 8); flush_dcache_range(address, address + 8); #endif if (err) return -EFAULT; /* Set up registers for signal handler */ regs->r1 = (unsigned long) frame; /* Signal handler args: */ regs->r5 = sig; /* arg 0: signum */ regs->r6 = (unsigned long) &frame->info; /* arg 1: siginfo */ regs->r7 = (unsigned long) &frame->uc; /* arg2: ucontext */ /* Offset to handle microblaze rtid r14, 0 */ regs->pc = (unsigned long)ksig->ka.sa.sa_handler; #ifdef DEBUG_SIG pr_info("SIG deliver (%s:%d): sp=%p pc=%08lx\n", current->comm, current->pid, frame, regs->pc); #endif return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michal Simek45691.75%753.85%
Richard Weinberger336.64%215.38%
Matt Fleming40.80%17.69%
Arnd Bergmann20.40%215.38%
Al Viro20.40%17.69%
Total497100.00%13100.00%

/* Handle restarting system calls */
static inline void handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) { switch (regs->r3) { case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND: if (!has_handler) goto do_restart; regs->r3 = -EINTR; break; case -ERESTARTSYS: if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { regs->r3 = -EINTR; break; } /* fallthrough */ case -ERESTARTNOINTR: do_restart: /* offset of 4 bytes to re-execute trap (brki) instruction */ regs->pc -= 4; break; } }

Contributors

PersonTokensPropCommitsCommitProp
Michal Simek96100.00%1100.00%
Total96100.00%1100.00%

/* * OK, we're invoking a handler */
static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) { sigset_t *oldset = sigmask_to_save(); int ret; /* Set up the stack frame */ ret = setup_rt_frame(ksig, oldset, regs); signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP)); }

Contributors

PersonTokensPropCommitsCommitProp
Michal Simek2550.00%114.29%
Al Viro1428.00%457.14%
Matt Fleming612.00%114.29%
Richard Weinberger510.00%114.29%
Total50100.00%7100.00%

/* * 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 void do_signal(struct pt_regs *regs, int in_syscall) { struct ksignal ksig; #ifdef DEBUG_SIG pr_info("do signal: %p %d\n", regs, in_syscall); pr_info("do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1, regs->r12, current_thread_info()->flags); #endif if (get_signal(&ksig)) { /* Whee! Actually deliver the signal. */ if (in_syscall) handle_restart(regs, &ksig.ka, 1); handle_signal(&ksig, regs); return; } if (in_syscall) handle_restart(regs, NULL, 0); /* * If there's no signal to deliver, we just put the saved sigmask * back. */ restore_saved_sigmask(); }

Contributors

PersonTokensPropCommitsCommitProp
Michal Simek9084.11%228.57%
Richard Weinberger98.41%114.29%
Al Viro54.67%342.86%
Arnd Bergmann32.80%114.29%
Total107100.00%7100.00%


asmlinkage void do_notify_resume(struct pt_regs *regs, int in_syscall) { if (test_thread_flag(TIF_SIGPENDING)) do_signal(regs, in_syscall); if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) tracehook_notify_resume(regs); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro3997.50%150.00%
Michal Simek12.50%150.00%
Total40100.00%2100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Michal Simek134686.12%934.62%
Arnd Bergmann795.05%27.69%
Al Viro724.61%934.62%
Richard Weinberger543.45%311.54%
Matt Fleming110.70%27.69%
Andrew Lutomirski10.06%13.85%
Total1563100.00%26100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.