📄 signal_64.c
字号:
/* * linux/arch/ppc64/kernel/signal.c * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * Derived from "arch/i386/kernel/signal.c" * Copyright (C) 1991, 1992 Linus Torvalds * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#include <linux/config.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/kernel.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/wait.h>#include <linux/unistd.h>#include <linux/stddef.h>#include <linux/elf.h>#include <linux/ptrace.h>#include <linux/module.h>#include <asm/sigcontext.h>#include <asm/ucontext.h>#include <asm/uaccess.h>#include <asm/pgtable.h>#include <asm/unistd.h>#include <asm/cacheflush.h>#include <asm/vdso.h>#define DEBUG_SIG 0#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))#define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs))#define FP_REGS_SIZE sizeof(elf_fpregset_t)#define TRAMP_TRACEBACK 3#define TRAMP_SIZE 6/* * When we have signals to deliver, we set up on the user stack, * going down from the original stack pointer: * 1) a rt_sigframe struct which contains the ucontext * 2) a gap of __SIGNAL_FRAMESIZE bytes which acts as a dummy caller * frame for the signal handler. */struct rt_sigframe { /* sys_rt_sigreturn requires the ucontext be the first field */ struct ucontext uc; unsigned long _unused[2]; unsigned int tramp[TRAMP_SIZE]; struct siginfo *pinfo; void *puc; struct siginfo info; /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */ char abigap[288];} __attribute__ ((aligned (16)));/* * Atomically swap in the new signal mask, and wait for a signal. */long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int p4, int p6, int p7, struct pt_regs *regs){ sigset_t saveset, newset; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) return -EINVAL; if (copy_from_user(&newset, unewset, sizeof(newset))) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); saveset = current->blocked; current->blocked = newset; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); regs->result = -EINTR; regs->gpr[3] = EINTR; regs->ccr |= 0x10000000; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(&saveset, regs)) return 0; }}long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5, unsigned long r6, unsigned long r7, unsigned long r8, struct pt_regs *regs){ return do_sigaltstack(uss, uoss, regs->gpr[1]);}/* * Set up the sigcontext for the signal frame. */static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, int signr, sigset_t *set, unsigned long handler){ /* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the * process never used altivec yet (MSR_VEC is zero in pt_regs of * the context). This is very important because we must ensure we * don't lose the VRSAVE content that may have been set prior to * the process doing its first vector operation * Userland shall check AT_HWCAP to know wether it can rely on the * v_regs pointer or not */#ifdef CONFIG_ALTIVEC elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *)(((unsigned long)sc->vmx_reserve + 15) & ~0xful);#endif long err = 0; flush_fp_to_thread(current);#ifdef CONFIG_ALTIVEC err |= __put_user(v_regs, &sc->v_regs); /* save altivec registers */ if (current->thread.used_vr) { flush_altivec_to_thread(current); /* Copy 33 vec registers (vr0..31 and vscr) to the stack */ err |= __copy_to_user(v_regs, current->thread.vr, 33 * sizeof(vector128)); /* set MSR_VEC in the MSR value in the frame to indicate that sc->v_reg) * contains valid data. */ regs->msr |= MSR_VEC; } /* We always copy to/from vrsave, it's 0 if we don't have or don't * use altivec. */ err |= __put_user(current->thread.vrsave, (u32 __user *)&v_regs[33]);#else /* CONFIG_ALTIVEC */ err |= __put_user(0, &sc->v_regs);#endif /* CONFIG_ALTIVEC */ err |= __put_user(&sc->gp_regs, &sc->regs); err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); err |= __put_user(signr, &sc->signal); err |= __put_user(handler, &sc->handler); if (set != NULL) err |= __put_user(set->sig[0], &sc->oldmask); return err;}/* * Restore the sigcontext from the signal frame. */static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, struct sigcontext __user *sc){#ifdef CONFIG_ALTIVEC elf_vrreg_t __user *v_regs;#endif unsigned long err = 0; unsigned long save_r13 = 0; elf_greg_t *gregs = (elf_greg_t *)regs;#ifdef CONFIG_ALTIVEC unsigned long msr;#endif int i; /* If this is not a signal return, we preserve the TLS in r13 */ if (!sig) save_r13 = regs->gpr[13]; /* copy everything before MSR */ err |= __copy_from_user(regs, &sc->gp_regs, PT_MSR*sizeof(unsigned long)); /* skip MSR and SOFTE */ for (i = PT_MSR+1; i <= PT_RESULT; i++) { if (i == PT_SOFTE) continue; err |= __get_user(gregs[i], &sc->gp_regs[i]); } if (!sig) regs->gpr[13] = save_r13; err |= __copy_from_user(¤t->thread.fpr, &sc->fp_regs, FP_REGS_SIZE); if (set != NULL) err |= __get_user(set->sig[0], &sc->oldmask);#ifdef CONFIG_ALTIVEC err |= __get_user(v_regs, &sc->v_regs); err |= __get_user(msr, &sc->gp_regs[PT_MSR]); if (err) return err; /* Copy 33 vec registers (vr0..31 and vscr) from the stack */ if (v_regs != 0 && (msr & MSR_VEC) != 0) err |= __copy_from_user(current->thread.vr, v_regs, 33 * sizeof(vector128)); else if (current->thread.used_vr) memset(current->thread.vr, 0, 33 * sizeof(vector128)); /* Always get VRSAVE back */ if (v_regs != 0) err |= __get_user(current->thread.vrsave, (u32 __user *)&v_regs[33]); else current->thread.vrsave = 0;#endif /* CONFIG_ALTIVEC */#ifndef CONFIG_SMP preempt_disable(); if (last_task_used_math == current) last_task_used_math = NULL; if (last_task_used_altivec == current) last_task_used_altivec = NULL; preempt_enable();#endif /* Force reload of FP/VEC */ regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC); return err;}/* * Allocate space for the signal frame */static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size){ unsigned long newsp; /* Default to using normal stack */ newsp = regs->gpr[1]; if (ka->sa.sa_flags & SA_ONSTACK) { if (! on_sig_stack(regs->gpr[1])) newsp = (current->sas_ss_sp + current->sas_ss_size); } return (void __user *)((newsp - frame_size) & -16ul);}/* * Setup the trampoline code on the stack */static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp){ int i; long err = 0; /* addi r1, r1, __SIGNAL_FRAMESIZE # Pop the dummy stackframe */ err |= __put_user(0x38210000UL | (__SIGNAL_FRAMESIZE & 0xffff), &tramp[0]); /* li r0, __NR_[rt_]sigreturn| */ err |= __put_user(0x38000000UL | (syscall & 0xffff), &tramp[1]); /* sc */ err |= __put_user(0x44000002UL, &tramp[2]); /* Minimal traceback info */ for (i=TRAMP_TRACEBACK; i < TRAMP_SIZE ;i++) err |= __put_user(0, &tramp[i]); if (!err) flush_icache_range((unsigned long) &tramp[0], (unsigned long) &tramp[TRAMP_SIZE]); return err;}/* * Restore the user process's signal mask (also used by signal32.c) */void restore_sigmask(sigset_t *set){ sigdelsetmask(set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = *set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -