[MIPS] signals: Share even more code.
native and compat do_signal and handle_signal are identical and can easily be unified. Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Родитель
38201fb23c
Коммит
151fd6acd9
|
@ -26,7 +26,6 @@
|
||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
#include <linux/kallsyms.h>
|
#include <linux/kallsyms.h>
|
||||||
|
|
||||||
#include <asm/abi.h>
|
|
||||||
#include <asm/bootinfo.h>
|
#include <asm/bootinfo.h>
|
||||||
#include <asm/cpu.h>
|
#include <asm/cpu.h>
|
||||||
#include <asm/dsp.h>
|
#include <asm/dsp.h>
|
||||||
|
@ -66,38 +65,6 @@ ATTRIB_NORET void cpu_idle(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Native o32 and N64 ABI without DSP ASE
|
|
||||||
*/
|
|
||||||
struct mips_abi mips_abi = {
|
|
||||||
.do_signal = do_signal,
|
|
||||||
#ifdef CONFIG_TRAD_SIGNALS
|
|
||||||
.setup_frame = setup_frame,
|
|
||||||
#endif
|
|
||||||
.setup_rt_frame = setup_rt_frame
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_MIPS32_O32
|
|
||||||
/*
|
|
||||||
* o32 compatibility on 64-bit kernels, without DSP ASE
|
|
||||||
*/
|
|
||||||
struct mips_abi mips_abi_32 = {
|
|
||||||
.do_signal = do_signal32,
|
|
||||||
.setup_frame = setup_frame_32,
|
|
||||||
.setup_rt_frame = setup_rt_frame_32
|
|
||||||
};
|
|
||||||
#endif /* CONFIG_MIPS32_O32 */
|
|
||||||
|
|
||||||
#ifdef CONFIG_MIPS32_N32
|
|
||||||
/*
|
|
||||||
* N32 on 64-bit kernels, without DSP ASE
|
|
||||||
*/
|
|
||||||
struct mips_abi mips_abi_n32 = {
|
|
||||||
.do_signal = do_signal,
|
|
||||||
.setup_rt_frame = setup_rt_frame_n32
|
|
||||||
};
|
|
||||||
#endif /* CONFIG_MIPS32_N32 */
|
|
||||||
|
|
||||||
asmlinkage void ret_from_fork(void);
|
asmlinkage void ret_from_fork(void);
|
||||||
|
|
||||||
void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
|
void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
|
||||||
|
|
|
@ -398,7 +398,7 @@ badframe:
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_TRAD_SIGNALS
|
#ifdef CONFIG_TRAD_SIGNALS
|
||||||
int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
|
static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
|
||||||
int signr, sigset_t *set)
|
int signr, sigset_t *set)
|
||||||
{
|
{
|
||||||
struct sigframe __user *frame;
|
struct sigframe __user *frame;
|
||||||
|
@ -443,7 +443,7 @@ give_sigsegv:
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
|
static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
|
||||||
int signr, sigset_t *set, siginfo_t *info)
|
int signr, sigset_t *set, siginfo_t *info)
|
||||||
{
|
{
|
||||||
struct rt_sigframe __user *frame;
|
struct rt_sigframe __user *frame;
|
||||||
|
@ -501,6 +501,14 @@ give_sigsegv:
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct mips_abi mips_abi = {
|
||||||
|
#ifdef CONFIG_TRAD_SIGNALS
|
||||||
|
.setup_frame = setup_frame,
|
||||||
|
#endif
|
||||||
|
.setup_rt_frame = setup_rt_frame,
|
||||||
|
.restart = __NR_restart_syscall
|
||||||
|
};
|
||||||
|
|
||||||
static int handle_signal(unsigned long sig, siginfo_t *info,
|
static int handle_signal(unsigned long sig, siginfo_t *info,
|
||||||
struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs)
|
struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
@ -539,7 +547,7 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_signal(struct pt_regs *regs)
|
static void do_signal(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct k_sigaction ka;
|
struct k_sigaction ka;
|
||||||
sigset_t *oldset;
|
sigset_t *oldset;
|
||||||
|
@ -589,7 +597,7 @@ void do_signal(struct pt_regs *regs)
|
||||||
regs->cp0_epc -= 8;
|
regs->cp0_epc -= 8;
|
||||||
}
|
}
|
||||||
if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
|
if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
|
||||||
regs->regs[2] = __NR_restart_syscall;
|
regs->regs[2] = current->thread.abi->restart;
|
||||||
regs->regs[7] = regs->regs[26];
|
regs->regs[7] = regs->regs[26];
|
||||||
regs->cp0_epc -= 4;
|
regs->cp0_epc -= 4;
|
||||||
}
|
}
|
||||||
|
@ -615,5 +623,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
|
||||||
{
|
{
|
||||||
/* deal with pending signal delivery */
|
/* deal with pending signal delivery */
|
||||||
if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
|
if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
|
||||||
current->thread.abi->do_signal(regs);
|
do_signal(regs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ typedef struct compat_siginfo {
|
||||||
*/
|
*/
|
||||||
#define __NR_O32_sigreturn 4119
|
#define __NR_O32_sigreturn 4119
|
||||||
#define __NR_O32_rt_sigreturn 4193
|
#define __NR_O32_rt_sigreturn 4193
|
||||||
#define __NR_O32_restart_syscall 4253
|
#define __NR_O32_restart_syscall 4253
|
||||||
|
|
||||||
/* 32-bit compatibility types */
|
/* 32-bit compatibility types */
|
||||||
|
|
||||||
|
@ -598,7 +598,7 @@ badframe:
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
|
static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
|
||||||
int signr, sigset_t *set)
|
int signr, sigset_t *set)
|
||||||
{
|
{
|
||||||
struct sigframe32 __user *frame;
|
struct sigframe32 __user *frame;
|
||||||
|
@ -644,7 +644,7 @@ give_sigsegv:
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
|
static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
|
||||||
int signr, sigset_t *set, siginfo_t *info)
|
int signr, sigset_t *set, siginfo_t *info)
|
||||||
{
|
{
|
||||||
struct rt_sigframe32 __user *frame;
|
struct rt_sigframe32 __user *frame;
|
||||||
|
@ -704,110 +704,14 @@ give_sigsegv:
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int handle_signal(unsigned long sig, siginfo_t *info,
|
/*
|
||||||
struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs)
|
* o32 compatibility on 64-bit kernels, without DSP ASE
|
||||||
{
|
*/
|
||||||
int ret;
|
struct mips_abi mips_abi_32 = {
|
||||||
|
.setup_frame = setup_frame_32,
|
||||||
switch (regs->regs[0]) {
|
.setup_rt_frame = setup_rt_frame_32,
|
||||||
case ERESTART_RESTARTBLOCK:
|
.restart = __NR_O32_restart_syscall
|
||||||
case ERESTARTNOHAND:
|
};
|
||||||
regs->regs[2] = EINTR;
|
|
||||||
break;
|
|
||||||
case ERESTARTSYS:
|
|
||||||
if (!(ka->sa.sa_flags & SA_RESTART)) {
|
|
||||||
regs->regs[2] = EINTR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* fallthrough */
|
|
||||||
case ERESTARTNOINTR: /* Userland will reload $v0. */
|
|
||||||
regs->regs[7] = regs->regs[26];
|
|
||||||
regs->cp0_epc -= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
regs->regs[0] = 0; /* Don't deal with this again. */
|
|
||||||
|
|
||||||
if (ka->sa.sa_flags & SA_SIGINFO)
|
|
||||||
ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info);
|
|
||||||
else
|
|
||||||
ret = current->thread.abi->setup_frame(ka, regs, sig, oldset);
|
|
||||||
|
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
|
||||||
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
|
||||||
if (!(ka->sa.sa_flags & SA_NODEFER))
|
|
||||||
sigaddset(¤t->blocked,sig);
|
|
||||||
recalc_sigpending();
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_signal32(struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
struct k_sigaction ka;
|
|
||||||
sigset_t *oldset;
|
|
||||||
siginfo_t info;
|
|
||||||
int signr;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We want the common case to go fast, which is why we may in certain
|
|
||||||
* cases get here from kernel mode. Just return without doing anything
|
|
||||||
* if so.
|
|
||||||
*/
|
|
||||||
if (!user_mode(regs))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
|
||||||
oldset = ¤t->saved_sigmask;
|
|
||||||
else
|
|
||||||
oldset = ¤t->blocked;
|
|
||||||
|
|
||||||
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
|
||||||
if (signr > 0) {
|
|
||||||
/* Whee! Actually deliver the signal. */
|
|
||||||
if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
|
|
||||||
/*
|
|
||||||
* A signal was successfully delivered; the saved
|
|
||||||
* sigmask will have been stored in the signal frame,
|
|
||||||
* and will be restored by sigreturn, so we can simply
|
|
||||||
* clear the TIF_RESTORE_SIGMASK flag.
|
|
||||||
*/
|
|
||||||
if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
|
||||||
clear_thread_flag(TIF_RESTORE_SIGMASK);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Who's code doesn't conform to the restartable syscall convention
|
|
||||||
* dies here!!! The li instruction, a single machine instruction,
|
|
||||||
* must directly be followed by the syscall instruction.
|
|
||||||
*/
|
|
||||||
if (regs->regs[0]) {
|
|
||||||
if (regs->regs[2] == ERESTARTNOHAND ||
|
|
||||||
regs->regs[2] == ERESTARTSYS ||
|
|
||||||
regs->regs[2] == ERESTARTNOINTR) {
|
|
||||||
regs->regs[7] = regs->regs[26];
|
|
||||||
regs->cp0_epc -= 8;
|
|
||||||
}
|
|
||||||
if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
|
|
||||||
regs->regs[2] = __NR_O32_restart_syscall;
|
|
||||||
regs->regs[7] = regs->regs[26];
|
|
||||||
regs->cp0_epc -= 4;
|
|
||||||
}
|
|
||||||
regs->regs[0] = 0; /* Don't deal with this again. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there's no signal to deliver, we just put the saved sigmask
|
|
||||||
* back
|
|
||||||
*/
|
|
||||||
if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
|
|
||||||
clear_thread_flag(TIF_RESTORE_SIGMASK);
|
|
||||||
sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
|
asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
|
||||||
struct sigaction32 __user *oact,
|
struct sigaction32 __user *oact,
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
|
#include <asm/abi.h>
|
||||||
#include <asm/asm.h>
|
#include <asm/asm.h>
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
#include <asm/compat-signal.h>
|
#include <asm/compat-signal.h>
|
||||||
|
@ -169,7 +170,7 @@ badframe:
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
int setup_rt_frame_n32(struct k_sigaction * ka,
|
static int setup_rt_frame_n32(struct k_sigaction * ka,
|
||||||
struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info)
|
struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info)
|
||||||
{
|
{
|
||||||
struct rt_sigframe_n32 __user *frame;
|
struct rt_sigframe_n32 __user *frame;
|
||||||
|
@ -228,3 +229,8 @@ give_sigsegv:
|
||||||
force_sigsegv(signr, current);
|
force_sigsegv(signr, current);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct mips_abi mips_abi_n32 = {
|
||||||
|
.setup_rt_frame = setup_rt_frame_n32,
|
||||||
|
.restart = __NR_N32_restart_syscall
|
||||||
|
};
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
#include <asm/siginfo.h>
|
#include <asm/siginfo.h>
|
||||||
|
|
||||||
struct mips_abi {
|
struct mips_abi {
|
||||||
void (* const do_signal)(struct pt_regs *regs);
|
|
||||||
int (* const setup_frame)(struct k_sigaction * ka,
|
int (* const setup_frame)(struct k_sigaction * ka,
|
||||||
struct pt_regs *regs, int signr,
|
struct pt_regs *regs, int signr,
|
||||||
sigset_t *set);
|
sigset_t *set);
|
||||||
int (* const setup_rt_frame)(struct k_sigaction * ka,
|
int (* const setup_rt_frame)(struct k_sigaction * ka,
|
||||||
struct pt_regs *regs, int signr,
|
struct pt_regs *regs, int signr,
|
||||||
sigset_t *set, siginfo_t *info);
|
sigset_t *set, siginfo_t *info);
|
||||||
|
const unsigned long restart;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _ASM_ABI_H */
|
#endif /* _ASM_ABI_H */
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
|
|
||||||
|
#include <asm/signal.h>
|
||||||
|
#include <asm/siginfo.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d,
|
static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d,
|
||||||
|
|
|
@ -137,23 +137,6 @@ typedef struct sigaltstack {
|
||||||
|
|
||||||
#define ptrace_signal_deliver(regs, cookie) do { } while (0)
|
#define ptrace_signal_deliver(regs, cookie) do { } while (0)
|
||||||
|
|
||||||
struct pt_regs;
|
|
||||||
extern void do_signal(struct pt_regs *regs);
|
|
||||||
extern void do_signal32(struct pt_regs *regs);
|
|
||||||
|
|
||||||
extern int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
|
|
||||||
int signr, sigset_t *set);
|
|
||||||
extern int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
|
|
||||||
int signr, sigset_t *set, siginfo_t *info);
|
|
||||||
|
|
||||||
extern int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
|
|
||||||
int signr, sigset_t *set);
|
|
||||||
extern int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
|
|
||||||
int signr, sigset_t *set, siginfo_t *info);
|
|
||||||
|
|
||||||
extern int setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs,
|
|
||||||
int signr, sigset_t *set, siginfo_t *info);
|
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
#endif /* _ASM_SIGNAL_H */
|
#endif /* _ASM_SIGNAL_H */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче