⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 signal.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		compat_val = sas_ss_flags(regs->gr[30]);				err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_flags);				DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &compat_frame->uc);		DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &compat_frame->uc.uc_mcontext);		err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext, 					&compat_frame->regs, regs, in_syscall);		sigset_64to32(&compat_set,set);		err |= __copy_to_user(&compat_frame->uc.uc_sigmask, &compat_set, sizeof(compat_set));	} else#endif	{			DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &frame->info);		err |= copy_siginfo_to_user(&frame->info, info);		err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);		err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);		err |= __put_user(sas_ss_flags(regs->gr[30]),				  &frame->uc.uc_stack.ss_flags);		DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &frame->uc);		DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &frame->uc.uc_mcontext);		err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall);		/* FIXME: Should probably be converted aswell for the compat case */		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));	}		if (err)		goto give_sigsegv;	/* Set up to return from userspace.  If provided, use a stub	   already in userspace. The first words of tramp are used to	   save the previous sigrestartblock trampoline that might be	   on the stack. We start the sigreturn trampoline at 	   SIGRESTARTBLOCK_TRAMP+X. */	err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0,			&frame->tramp[SIGRESTARTBLOCK_TRAMP+0]);	err |= __put_user(INSN_LDI_R20, 			&frame->tramp[SIGRESTARTBLOCK_TRAMP+1]);	err |= __put_user(INSN_BLE_SR2_R0, 			&frame->tramp[SIGRESTARTBLOCK_TRAMP+2]);	err |= __put_user(INSN_NOP, &frame->tramp[SIGRESTARTBLOCK_TRAMP+3]);#if DEBUG_SIG	/* Assert that we're flushing in the correct space... */	{		int sid;		asm ("mfsp %%sr3,%0" : "=r" (sid));		DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n",		       sid, frame->tramp);	}#endif	flush_user_dcache_range((unsigned long) &frame->tramp[0],			   (unsigned long) &frame->tramp[TRAMP_SIZE]);	flush_user_icache_range((unsigned long) &frame->tramp[0],			   (unsigned long) &frame->tramp[TRAMP_SIZE]);	/* TRAMP Words 0-4, Lenght 5 = SIGRESTARTBLOCK_TRAMP	 * TRAMP Words 5-9, Length 4 = SIGRETURN_TRAMP	 * So the SIGRETURN_TRAMP is at the end of SIGRESTARTBLOCK_TRAMP	 */	rp = (unsigned long) &frame->tramp[SIGRESTARTBLOCK_TRAMP];	if (err)		goto give_sigsegv;	haddr = A(ka->sa.sa_handler);	/* The sa_handler may be a pointer to a function descriptor */#ifdef __LP64__	if(personality(current->personality) == PER_LINUX32) {#endif		if (haddr & PA_PLABEL_FDESC) {			Elf32_Fdesc fdesc;			Elf32_Fdesc *ufdesc = (Elf32_Fdesc *)A(haddr & ~3);			err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));			if (err)				goto give_sigsegv;			haddr = fdesc.addr;			regs->gr[19] = fdesc.gp;		}#ifdef __LP64__	} else {		Elf64_Fdesc fdesc;		Elf64_Fdesc *ufdesc = (Elf64_Fdesc *)A(haddr & ~3);				err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));				if (err)			goto give_sigsegv;				haddr = fdesc.addr;		regs->gr[19] = fdesc.gp;		DBG(1,"setup_rt_frame: 64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n",		     haddr, regs->gr[19], in_syscall);	}#endif	/* The syscall return path will create IAOQ values from r31.	 */	sigframe_size = PARISC_RT_SIGFRAME_SIZE;#ifdef __LP64__	if(personality(current->personality) == PER_LINUX32)		sigframe_size = PARISC_RT_SIGFRAME_SIZE32;#endif	if (in_syscall) {		regs->gr[31] = haddr;#ifdef __LP64__		if(personality(current->personality) == PER_LINUX)			sigframe_size |= 1;#endif	} else {		unsigned long psw = USER_PSW;#ifdef __LP64__		if(personality(current->personality) == PER_LINUX)			psw |= PSW_W;#endif		regs->gr[0] = psw;		regs->iaoq[0] = haddr | 3;		regs->iaoq[1] = regs->iaoq[0] + 4;	}	regs->gr[2]  = rp;                /* userland return pointer */	regs->gr[26] = sig;               /* signal number */	#ifdef __LP64__	if(personality(current->personality) == PER_LINUX32){		regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */		regs->gr[24] = A(&compat_frame->uc);   /* ucontext pointer */	} else#endif	{				regs->gr[25] = A(&frame->info); /* siginfo pointer */		regs->gr[24] = A(&frame->uc);   /* ucontext pointer */	}		DBG(1,"setup_rt_frame: making sigreturn frame: %#lx + %#lx = %#lx\n",	       regs->gr[30], sigframe_size,	       regs->gr[30] + sigframe_size);	/* Raise the user stack pointer to make a proper call frame. */	regs->gr[30] = (A(frame) + sigframe_size);	DBG(1,"setup_rt_frame: sig deliver (%s,%d) frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",	       current->comm, current->pid, frame, regs->gr[30],	       regs->iaoq[0], regs->iaoq[1], rp);	return 1;give_sigsegv:	DBG(1,"setup_rt_frame: sending SIGSEGV\n");	if (sig == SIGSEGV)		ka->sa.sa_handler = SIG_DFL;	si.si_signo = SIGSEGV;	si.si_errno = 0;	si.si_code = SI_KERNEL;	si.si_pid = current->pid;	si.si_uid = current->uid;	si.si_addr = frame;	force_sig_info(SIGSEGV, &si, current);	return 0;}/* * OK, we're invoking a handler. */	static longhandle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,	      struct pt_regs *regs, int in_syscall){	struct k_sigaction *ka = &current->sighand->action[sig-1];	DBG(1,"handle_signal: sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p\n",	       sig, ka, info, oldset, regs);		/* Set up the stack frame */	if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))		return 0;	if (ka->sa.sa_flags & SA_ONESHOT)		ka->sa.sa_handler = SIG_DFL;	if (!(ka->sa.sa_flags & SA_NODEFER)) {		spin_lock_irq(&current->sighand->siglock);		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);		sigaddset(&current->blocked,sig);		recalc_sigpending();		spin_unlock_irq(&current->sighand->siglock);	}	return 1;}/* * 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. * * We need to be able to restore the syscall arguments (r21-r26) to * restart syscalls.  Thus, the syscall path should save them in the * pt_regs structure (it's okay to do so since they are caller-save * registers).  As noted below, the syscall number gets restored for * us due to the magic of delayed branching. */asmlinkage intdo_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall){	siginfo_t info;	struct k_sigaction *ka;	int signr;	DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n",	       oldset, regs, regs->sr[7], in_syscall);	/* Everyone else checks to see if they are in kernel mode at	   this point and exits if that's the case.  I'm not sure why	   we would be called in that case, but for some reason we	   are. */	if (!oldset)		oldset = &current->blocked;	DBG(1,"do_signal: oldset %08lx / %08lx\n", 		oldset->sig[0], oldset->sig[1]);	signr = get_signal_to_deliver(&info, regs, NULL);	DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); 		if (signr > 0) {		/* Restart a system call if necessary. */		if (in_syscall) {			/* Check the return code */			switch (regs->gr[28]) {		        case -ERESTART_RESTARTBLOCK:				current_thread_info()->restart_block.fn = do_no_restart_syscall;			case -ERESTARTNOHAND:				DBG(1,"ERESTARTNOHAND: returning -EINTR\n");				regs->gr[28] = -EINTR;				break;			case -ERESTARTSYS:				ka = &current->sighand->action[signr-1];				if (!(ka->sa.sa_flags & SA_RESTART)) {					DBG(1,"ERESTARTSYS: putting -EINTR\n");					regs->gr[28] = -EINTR;					break;				}			/* fallthrough */			case -ERESTARTNOINTR:				/* A syscall is just a branch, so all                                   we have to do is fiddle the return                                   pointer. */				regs->gr[31] -= 8; /* delayed branching */				/* Preserve original r28. */				regs->gr[28] = regs->orig_r28;				break;			}		}		/* Whee!  Actually deliver the signal.  If the		   delivery failed, we need to continue to iterate in		   this loop so we can deliver the SIGSEGV... */		if (handle_signal(signr, &info, oldset, regs, in_syscall)) {			DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n",				regs->gr[28]);			return 1;		}	}	/* Did we come from a system call? */	if (in_syscall) {		/* Restart the system call - no handlers present */		if (regs->gr[28] == -ERESTART_RESTARTBLOCK) {			unsigned int *usp = (unsigned int *)regs->gr[30];			/* Setup a trampoline to restart the syscall			 * with __NR_restart_syscall			 *			 *  0: <return address (orig r31)>			 *  4: <2nd half for 64-bit>			 *  8: ldw 0(%sp), %r31			 * 12: be 0x100(%sr2, %r0)			 * 16: ldi __NR_restart_syscall, %r20			 */#ifndef __LP64__			put_user(regs->gr[31], &usp[0]);			put_user(0x0fc0109f, &usp[2]);#else			put_user(regs->gr[31] >> 32, &usp[0]);			put_user(regs->gr[31] & 0xffffffff, &usp[1]);			put_user(0x0fc010df, &usp[2]);#endif			put_user(0xe0008200, &usp[3]);			put_user(0x34140000, &usp[4]);			/* Stack is 64-byte aligned, and we only 			 * need to flush 1 cache line */			asm("fdc 0(%%sr3, %0)\n"			    "fic 0(%%sr3, %0)\n"			    "sync\n"			    : : "r"(regs->gr[30]));			regs->gr[31] = regs->gr[30] + 8;			/* Preserve original r28. */			regs->gr[28] = regs->orig_r28;		} else if (regs->gr[28] == -ERESTARTNOHAND ||		           regs->gr[28] == -ERESTARTSYS ||		           regs->gr[28] == -ERESTARTNOINTR) {			/* Hooray for delayed branching.  We don't                           have to restore %r20 (the system call                           number) because it gets loaded in the delay                           slot of the branch external instruction. */			regs->gr[31] -= 8;			/* Preserve original r28. */			regs->gr[28] = regs->orig_r28;		}	}		DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", 		regs->gr[28]);	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -