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

📄 signal.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 2 页
字号:
		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 __user *ufdesc = (Elf32_Fdesc __user *)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 __user *ufdesc = (Elf64_Fdesc __user *)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		/* If we are singlestepping, arrange a trap to be delivered		   when we return to userspace. Note the semantics -- we		   should trap before the first insn in the handler is		   executed. Ref:			http://sources.redhat.com/ml/gdb/2004-11/msg00245.html		 */		if (pa_psw(current)->r) {			pa_psw(current)->r = 0;			psw |= PSW_R;			mtctl(-1, 0);		}		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, struct k_sigaction *ka,		sigset_t *oldset, struct pt_regs *regs, int in_syscall){	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;	spin_lock_irq(&current->sighand->siglock);	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);	if (!(ka->sa.sa_flags & SA_NODEFER))		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]);	/* May need to force signal if handle_signal failed to deliver */	while (1) {	  		signr = get_signal_to_deliver(&info, &ka, regs, NULL);		DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); 			if (signr <= 0)		  break;				/* 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:				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, &ka, oldset, regs, in_syscall)) {			DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n",				regs->gr[28]);			return 1;		}	}	/* end of while(1) looping forever if we can't force a signal */	/* 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 + -