📄 ia32_signal.c
字号:
/* * IA32 Architecture-specific signal handling support. * * Copyright (C) 1999, 2001-2002, 2005 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> * * Derived from i386 and Alpha versions. */#include <linux/errno.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/personality.h>#include <linux/ptrace.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/stddef.h>#include <linux/syscalls.h>#include <linux/unistd.h>#include <linux/wait.h>#include <linux/compat.h>#include <asm/intrinsics.h>#include <asm/uaccess.h>#include <asm/rse.h>#include <asm/sigcontext.h>#include "ia32priv.h"#include "../kernel/sigframe.h"#define A(__x) ((unsigned long)(__x))#define DEBUG_SIG 0#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))#define __IA32_NR_sigreturn 119#define __IA32_NR_rt_sigreturn 173struct sigframe_ia32{ int pretcode; int sig; struct sigcontext_ia32 sc; struct _fpstate_ia32 fpstate; unsigned int extramask[_COMPAT_NSIG_WORDS-1]; char retcode[8];};struct rt_sigframe_ia32{ int pretcode; int sig; int pinfo; int puc; compat_siginfo_t info; struct ucontext_ia32 uc; struct _fpstate_ia32 fpstate; char retcode[8];};intcopy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from){ unsigned long tmp; int err; if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t))) return -EFAULT; err = __get_user(to->si_signo, &from->si_signo); err |= __get_user(to->si_errno, &from->si_errno); err |= __get_user(to->si_code, &from->si_code); if (to->si_code < 0) err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { switch (to->si_code >> 16) { case __SI_CHLD >> 16: err |= __get_user(to->si_utime, &from->si_utime); err |= __get_user(to->si_stime, &from->si_stime); err |= __get_user(to->si_status, &from->si_status); default: err |= __get_user(to->si_pid, &from->si_pid); err |= __get_user(to->si_uid, &from->si_uid); break; case __SI_FAULT >> 16: err |= __get_user(tmp, &from->si_addr); to->si_addr = (void __user *) tmp; break; case __SI_POLL >> 16: err |= __get_user(to->si_band, &from->si_band); err |= __get_user(to->si_fd, &from->si_fd); break; case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case __SI_MESGQ >> 16: err |= __get_user(to->si_pid, &from->si_pid); err |= __get_user(to->si_uid, &from->si_uid); err |= __get_user(to->si_int, &from->si_int); break; } } return err;}intcopy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from){ unsigned int addr; int err; if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) return -EFAULT; /* If you change siginfo_t structure, please be sure this code is fixed accordingly. It should never copy any pad contained in the structure to avoid security leaks, but must copy the generic 3 ints plus the relevant union member. This routine must convert siginfo from 64bit to 32bit as well at the same time. */ err = __put_user(from->si_signo, &to->si_signo); err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user((short)from->si_code, &to->si_code); if (from->si_code < 0) err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { switch (from->si_code >> 16) { case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_status, &to->si_status); default: err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); break; case __SI_FAULT >> 16: /* avoid type-checking warnings by copying _pad[0] in lieu of si_addr... */ err |= __put_user(from->_sifields._pad[0], &to->si_addr); break; case __SI_POLL >> 16: err |= __put_user(from->si_band, &to->si_band); err |= __put_user(from->si_fd, &to->si_fd); break; case __SI_TIMER >> 16: err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_overrun, &to->si_overrun); addr = (unsigned long) from->si_ptr; err |= __put_user(addr, &to->si_ptr); break; case __SI_RT >> 16: /* Not generated by the kernel as of now. */ case __SI_MESGQ >> 16: err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_pid, &to->si_pid); addr = (unsigned long) from->si_ptr; err |= __put_user(addr, &to->si_ptr); break; } } return err;}/* * SAVE and RESTORE of ia32 fpstate info, from ia64 current state * Used in exception handler to pass the fpstate to the user, and restore * the fpstate while returning from the exception handler. * * fpstate info and their mapping to IA64 regs: * fpstate REG(BITS) Attribute Comments * cw ar.fcr(0:12) with bits 7 and 6 not used * sw ar.fsr(0:15) * tag ar.fsr(16:31) with odd numbered bits not used * (read returns 0, writes ignored) * ipoff ar.fir(0:31) * cssel ar.fir(32:47) * dataoff ar.fdr(0:31) * datasel ar.fdr(32:47) * * _st[(0+TOS)%8] f8 * _st[(1+TOS)%8] f9 * _st[(2+TOS)%8] f10 * _st[(3+TOS)%8] f11 (f8..f11 from ptregs) * : : : (f12..f15 from live reg) * : : : * _st[(7+TOS)%8] f15 TOS=sw.top(bits11:13) * * status Same as sw RO * magic 0 as X86_FXSR_MAGIC in ia32 * mxcsr Bits(7:15)=ar.fcr(39:47) * Bits(0:5) =ar.fsr(32:37) with bit 6 reserved * _xmm[0..7] f16..f31 (live registers) * with _xmm[0] * Bit(64:127)=f17(0:63) * Bit(0:63)=f16(0:63) * All other fields unused... */static intsave_ia32_fpstate_live (struct _fpstate_ia32 __user *save){ struct task_struct *tsk = current; struct pt_regs *ptp; struct _fpreg_ia32 *fpregp; char buf[32]; unsigned long fsr, fcr, fir, fdr; unsigned long new_fsr; unsigned long num128[2]; unsigned long mxcsr=0; int fp_tos, fr8_st_map; if (!access_ok(VERIFY_WRITE, save, sizeof(*save))) return -EFAULT; /* Read in fsr, fcr, fir, fdr and copy onto fpstate */ fsr = ia64_getreg(_IA64_REG_AR_FSR); fcr = ia64_getreg(_IA64_REG_AR_FCR); fir = ia64_getreg(_IA64_REG_AR_FIR); fdr = ia64_getreg(_IA64_REG_AR_FDR); /* * We need to clear the exception state before calling the signal handler. Clear * the bits 15, bits 0-7 in fp status word. Similar to the functionality of fnclex * instruction. */ new_fsr = fsr & ~0x80ff; ia64_setreg(_IA64_REG_AR_FSR, new_fsr); __put_user(fcr & 0xffff, &save->cw); __put_user(fsr & 0xffff, &save->sw); __put_user((fsr>>16) & 0xffff, &save->tag); __put_user(fir, &save->ipoff); __put_user((fir>>32) & 0xffff, &save->cssel); __put_user(fdr, &save->dataoff); __put_user((fdr>>32) & 0xffff, &save->datasel); __put_user(fsr & 0xffff, &save->status); mxcsr = ((fcr>>32) & 0xff80) | ((fsr>>32) & 0x3f); __put_user(mxcsr & 0xffff, &save->mxcsr); __put_user( 0, &save->magic); //#define X86_FXSR_MAGIC 0x0000 /* * save f8..f11 from pt_regs * save f12..f15 from live register set */ /* * Find the location where f8 has to go in fp reg stack. This depends on * TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps * to. */ fp_tos = (fsr>>11)&0x7; fr8_st_map = (8-fp_tos)&0x7; ptp = ia64_task_regs(tsk); fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15); ia64f2ia32f(fpregp, &ptp->f8); copy_to_user(&save->_st[(0+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); ia64f2ia32f(fpregp, &ptp->f9); copy_to_user(&save->_st[(1+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); ia64f2ia32f(fpregp, &ptp->f10); copy_to_user(&save->_st[(2+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); ia64f2ia32f(fpregp, &ptp->f11); copy_to_user(&save->_st[(3+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); ia64_stfe(fpregp, 12); copy_to_user(&save->_st[(4+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); ia64_stfe(fpregp, 13); copy_to_user(&save->_st[(5+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); ia64_stfe(fpregp, 14); copy_to_user(&save->_st[(6+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); ia64_stfe(fpregp, 15); copy_to_user(&save->_st[(7+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); ia64_stf8(&num128[0], 16); ia64_stf8(&num128[1], 17); copy_to_user(&save->_xmm[0], num128, sizeof(struct _xmmreg_ia32)); ia64_stf8(&num128[0], 18); ia64_stf8(&num128[1], 19); copy_to_user(&save->_xmm[1], num128, sizeof(struct _xmmreg_ia32)); ia64_stf8(&num128[0], 20); ia64_stf8(&num128[1], 21); copy_to_user(&save->_xmm[2], num128, sizeof(struct _xmmreg_ia32)); ia64_stf8(&num128[0], 22); ia64_stf8(&num128[1], 23); copy_to_user(&save->_xmm[3], num128, sizeof(struct _xmmreg_ia32)); ia64_stf8(&num128[0], 24); ia64_stf8(&num128[1], 25); copy_to_user(&save->_xmm[4], num128, sizeof(struct _xmmreg_ia32)); ia64_stf8(&num128[0], 26); ia64_stf8(&num128[1], 27); copy_to_user(&save->_xmm[5], num128, sizeof(struct _xmmreg_ia32)); ia64_stf8(&num128[0], 28); ia64_stf8(&num128[1], 29); copy_to_user(&save->_xmm[6], num128, sizeof(struct _xmmreg_ia32)); ia64_stf8(&num128[0], 30); ia64_stf8(&num128[1], 31); copy_to_user(&save->_xmm[7], num128, sizeof(struct _xmmreg_ia32)); return 0;}static intrestore_ia32_fpstate_live (struct _fpstate_ia32 __user *save){ struct task_struct *tsk = current; struct pt_regs *ptp; unsigned int lo, hi; unsigned long num128[2]; unsigned long num64, mxcsr; struct _fpreg_ia32 *fpregp; char buf[32]; unsigned long fsr, fcr, fir, fdr; int fp_tos, fr8_st_map; if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EFAULT); /* * Updating fsr, fcr, fir, fdr. * Just a bit more complicated than save. * - Need to make sure that we don't write any value other than the * specific fpstate info * - Need to make sure that the untouched part of frs, fdr, fir, fcr * should remain same while writing. * So, we do a read, change specific fields and write. */ fsr = ia64_getreg(_IA64_REG_AR_FSR); fcr = ia64_getreg(_IA64_REG_AR_FCR); fir = ia64_getreg(_IA64_REG_AR_FIR); fdr = ia64_getreg(_IA64_REG_AR_FDR); __get_user(mxcsr, (unsigned int __user *)&save->mxcsr); /* setting bits 0..5 8..12 with cw and 39..47 from mxcsr */ __get_user(lo, (unsigned int __user *)&save->cw); num64 = mxcsr & 0xff10; num64 = (num64 << 32) | (lo & 0x1f3f);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -