📄 i386-kernel-signal.c
字号:
/* * linux/arch/i386/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds * * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson */#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/ptrace.h>#include <linux/unistd.h>#include <linux/stddef.h>#include <asm/ucontext.h>#include <asm/uaccess.h>#define DEBUG_SIG 0#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru);asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));/* * Atomically swap in the new signal mask, and wait for a signal. */asmlinkage intsys_sigsuspend(int history0, int history1, old_sigset_t mask){ struct pt_regs * regs = (struct pt_regs *) &history0; sigset_t saveset; mask &= _BLOCKABLE; spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->eax = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(regs, &saveset)) return -EINTR; }}asmlinkage intsys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize){ struct pt_regs * regs = (struct pt_regs *) &unewset; 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->sigmask_lock); saveset = current->blocked; current->blocked = newset; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->eax = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(regs, &saveset)) return -EINTR; }}asmlinkage int sys_sigaction(int sig, const struct old_sigaction *act, struct old_sigaction *oact){ struct k_sigaction new_ka, old_ka; int ret; if (act) { old_sigset_t mask; if (verify_area(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) return -EFAULT; __get_user(new_ka.sa.sa_flags, &act->sa_flags); __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) return -EFAULT; __put_user(old_ka.sa.sa_flags, &oact->sa_flags); __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret;}asmlinkage intsys_sigaltstack(const stack_t *uss, stack_t *uoss){ struct pt_regs *regs = (struct pt_regs *) &uss; return do_sigaltstack(uss, uoss, regs->esp);}/* * Do a signal return; undo the signal stack. */struct sigframe{ char *pretcode; int sig; struct sigcontext sc; struct _fpstate fpstate; unsigned long extramask[_NSIG_WORDS-1]; char retcode[8];};struct rt_sigframe{ char *pretcode; int sig; struct siginfo *pinfo; void *puc; struct siginfo info; struct ucontext uc; struct _fpstate fpstate; char retcode[8];};static inline int restore_i387_hard(struct _fpstate *buf){ struct task_struct *tsk = current; clear_fpu(tsk); return __copy_from_user(&tsk->tss.i387.hard, buf, sizeof(*buf));}static inline int restore_i387(struct _fpstate *buf){ int err;#ifndef CONFIG_MATH_EMULATION err = restore_i387_hard(buf);#else if (boot_cpu_data.hard_math) err = restore_i387_hard(buf); else err = restore_i387_soft(¤t->tss.i387.soft, buf);#endif current->used_math = 1; return err;}static intrestore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *peax){ unsigned int err = 0;#define COPY(x) err |= __get_user(regs->x, &sc->x)#define COPY_SEG(seg) \ { unsigned short tmp; \ err |= __get_user(tmp, &sc->seg); \ regs->x##seg = tmp; }#define COPY_SEG_STRICT(seg) \ { unsigned short tmp; \ err |= __get_user(tmp, &sc->seg); \ regs->x##seg = tmp|3; }#define GET_SEG(seg) \ { unsigned short tmp; \ err |= __get_user(tmp, &sc->seg); \ loadsegment(seg,tmp); } GET_SEG(gs); GET_SEG(fs); COPY_SEG(es); COPY_SEG(ds); COPY(edi); COPY(esi); COPY(ebp); COPY(esp); COPY(ebx); COPY(edx); COPY(ecx); COPY(eip); COPY_SEG_STRICT(cs); COPY_SEG_STRICT(ss); { unsigned int tmpflags; err |= __get_user(tmpflags, &sc->eflags); regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); regs->orig_eax = -1; /* disable syscall checks */ } { struct _fpstate * buf; err |= __get_user(buf, &sc->fpstate); if (buf) { if (verify_area(VERIFY_READ, buf, sizeof(*buf))) goto badframe; err |= restore_i387(buf); } } err |= __get_user(*peax, &sc->eax); return err;badframe: return 1;}asmlinkage int sys_sigreturn(unsigned long __unused){ struct pt_regs *regs = (struct pt_regs *) &__unused; struct sigframe *frame = (struct sigframe *)(regs->esp - 8); sigset_t set; int eax; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask)))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); if (restore_sigcontext(regs, &frame->sc, &eax)) goto badframe; return eax;badframe: force_sig(SIGSEGV, current); return 0;} asmlinkage int sys_rt_sigreturn(unsigned long __unused){ struct pt_regs *regs = (struct pt_regs *) &__unused; struct rt_sigframe *frame = (struct rt_sigframe *)(regs->esp - 4); sigset_t set; stack_t st; int eax; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax)) goto badframe; if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ do_sigaltstack(&st, NULL, regs->esp); return eax;badframe: force_sig(SIGSEGV, current); return 0;} /* * Set up a signal frame. */static inline int save_i387_hard(struct _fpstate * buf){ struct task_struct *tsk = current; unlazy_fpu(tsk); tsk->tss.i387.hard.status = tsk->tss.i387.hard.swd; if (__copy_to_user(buf, &tsk->tss.i387.hard, sizeof(*buf))) return -1; return 1;}static int save_i387(struct _fpstate *buf){ if (!current->used_math) return 0; /* This will cause a "finit" to be triggered by the next attempted FPU operation by the 'current' process. */ current->used_math = 0;#ifndef CONFIG_MATH_EMULATION return save_i387_hard(buf);#else return boot_cpu_data.hard_math ? save_i387_hard(buf) : save_i387_soft(¤t->tss.i387.soft, buf);#endif}static intsetup_sigcontext(struct sigcontext *sc, struct _fpstate *fpstate, struct pt_regs *regs, unsigned long mask){ int tmp, err = 0; tmp = 0; __asm__("movl %%gs,%w0" : "=r"(tmp): "0"(tmp)); err |= __put_user(tmp, (unsigned int *)&sc->gs); __asm__("movl %%fs,%w0" : "=r"(tmp): "0"(tmp)); err |= __put_user(tmp, (unsigned int *)&sc->fs); err |= __put_user(regs->xes, (unsigned int *)&sc->es); err |= __put_user(regs->xds, (unsigned int *)&sc->ds); err |= __put_user(regs->edi, &sc->edi); err |= __put_user(regs->esi, &sc->esi); err |= __put_user(regs->ebp, &sc->ebp); err |= __put_user(regs->esp, &sc->esp); err |= __put_user(regs->ebx, &sc->ebx); err |= __put_user(regs->edx, &sc->edx); err |= __put_user(regs->ecx, &sc->ecx); err |= __put_user(regs->eax, &sc->eax); err |= __put_user(current->tss.trap_no, &sc->trapno); err |= __put_user(current->tss.error_code, &sc->err); err |= __put_user(regs->eip, &sc->eip); err |= __put_user(regs->xcs, (unsigned int *)&sc->cs); err |= __put_user(regs->eflags, &sc->eflags); err |= __put_user(regs->esp, &sc->esp_at_signal); err |= __put_user(regs->xss, (unsigned int *)&sc->ss); tmp = save_i387(fpstate); if (tmp < 0) err = 1; else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -