mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-22 14:41:27 +00:00
Merge branch 'x86/signal' into core/signal
This commit is contained in:
commit
84e9c95ad9
3 changed files with 133 additions and 90 deletions
|
@ -351,31 +351,28 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
|
||||||
savesegment(es, tmp);
|
savesegment(es, tmp);
|
||||||
err |= __put_user(tmp, (unsigned int __user *)&sc->es);
|
err |= __put_user(tmp, (unsigned int __user *)&sc->es);
|
||||||
|
|
||||||
err |= __put_user((u32)regs->di, &sc->di);
|
err |= __put_user(regs->di, &sc->di);
|
||||||
err |= __put_user((u32)regs->si, &sc->si);
|
err |= __put_user(regs->si, &sc->si);
|
||||||
err |= __put_user((u32)regs->bp, &sc->bp);
|
err |= __put_user(regs->bp, &sc->bp);
|
||||||
err |= __put_user((u32)regs->sp, &sc->sp);
|
err |= __put_user(regs->sp, &sc->sp);
|
||||||
err |= __put_user((u32)regs->bx, &sc->bx);
|
err |= __put_user(regs->bx, &sc->bx);
|
||||||
err |= __put_user((u32)regs->dx, &sc->dx);
|
err |= __put_user(regs->dx, &sc->dx);
|
||||||
err |= __put_user((u32)regs->cx, &sc->cx);
|
err |= __put_user(regs->cx, &sc->cx);
|
||||||
err |= __put_user((u32)regs->ax, &sc->ax);
|
err |= __put_user(regs->ax, &sc->ax);
|
||||||
err |= __put_user((u32)regs->cs, &sc->cs);
|
err |= __put_user(regs->cs, &sc->cs);
|
||||||
err |= __put_user((u32)regs->ss, &sc->ss);
|
err |= __put_user(regs->ss, &sc->ss);
|
||||||
err |= __put_user(current->thread.trap_no, &sc->trapno);
|
err |= __put_user(current->thread.trap_no, &sc->trapno);
|
||||||
err |= __put_user(current->thread.error_code, &sc->err);
|
err |= __put_user(current->thread.error_code, &sc->err);
|
||||||
err |= __put_user((u32)regs->ip, &sc->ip);
|
err |= __put_user(regs->ip, &sc->ip);
|
||||||
err |= __put_user((u32)regs->flags, &sc->flags);
|
err |= __put_user(regs->flags, &sc->flags);
|
||||||
err |= __put_user((u32)regs->sp, &sc->sp_at_signal);
|
err |= __put_user(regs->sp, &sc->sp_at_signal);
|
||||||
|
|
||||||
tmp = save_i387_xstate_ia32(fpstate);
|
tmp = save_i387_xstate_ia32(fpstate);
|
||||||
if (tmp < 0)
|
if (tmp < 0)
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
else {
|
else
|
||||||
clear_used_math();
|
|
||||||
stts();
|
|
||||||
err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
|
err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
|
||||||
&sc->fpstate);
|
&sc->fpstate);
|
||||||
}
|
|
||||||
|
|
||||||
/* non-iBCS2 extensions.. */
|
/* non-iBCS2 extensions.. */
|
||||||
err |= __put_user(mask, &sc->oldmask);
|
err |= __put_user(mask, &sc->oldmask);
|
||||||
|
|
|
@ -113,6 +113,27 @@ asmlinkage int sys_sigaltstack(unsigned long bx)
|
||||||
return do_sigaltstack(uss, uoss, regs->sp);
|
return do_sigaltstack(uss, uoss, regs->sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define COPY(x) { \
|
||||||
|
err |= __get_user(regs->x, &sc->x); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COPY_SEG(seg) { \
|
||||||
|
unsigned short tmp; \
|
||||||
|
err |= __get_user(tmp, &sc->seg); \
|
||||||
|
regs->seg = tmp; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COPY_SEG_STRICT(seg) { \
|
||||||
|
unsigned short tmp; \
|
||||||
|
err |= __get_user(tmp, &sc->seg); \
|
||||||
|
regs->seg = tmp | 3; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GET_SEG(seg) { \
|
||||||
|
unsigned short tmp; \
|
||||||
|
err |= __get_user(tmp, &sc->seg); \
|
||||||
|
loadsegment(seg, tmp); \
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do a signal return; undo the signal stack.
|
* Do a signal return; undo the signal stack.
|
||||||
|
@ -121,28 +142,13 @@ static int
|
||||||
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
||||||
unsigned long *pax)
|
unsigned long *pax)
|
||||||
{
|
{
|
||||||
|
void __user *buf;
|
||||||
|
unsigned int tmpflags;
|
||||||
unsigned int err = 0;
|
unsigned int err = 0;
|
||||||
|
|
||||||
/* Always make any pending restarted system calls return -EINTR */
|
/* Always make any pending restarted system calls return -EINTR */
|
||||||
current_thread_info()->restart_block.fn = do_no_restart_syscall;
|
current_thread_info()->restart_block.fn = do_no_restart_syscall;
|
||||||
|
|
||||||
#define COPY(x) err |= __get_user(regs->x, &sc->x)
|
|
||||||
|
|
||||||
#define COPY_SEG(seg) \
|
|
||||||
{ unsigned short tmp; \
|
|
||||||
err |= __get_user(tmp, &sc->seg); \
|
|
||||||
regs->seg = tmp; }
|
|
||||||
|
|
||||||
#define COPY_SEG_STRICT(seg) \
|
|
||||||
{ unsigned short tmp; \
|
|
||||||
err |= __get_user(tmp, &sc->seg); \
|
|
||||||
regs->seg = tmp|3; }
|
|
||||||
|
|
||||||
#define GET_SEG(seg) \
|
|
||||||
{ unsigned short tmp; \
|
|
||||||
err |= __get_user(tmp, &sc->seg); \
|
|
||||||
loadsegment(seg, tmp); }
|
|
||||||
|
|
||||||
GET_SEG(gs);
|
GET_SEG(gs);
|
||||||
COPY_SEG(fs);
|
COPY_SEG(fs);
|
||||||
COPY_SEG(es);
|
COPY_SEG(es);
|
||||||
|
@ -152,21 +158,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
||||||
COPY_SEG_STRICT(cs);
|
COPY_SEG_STRICT(cs);
|
||||||
COPY_SEG_STRICT(ss);
|
COPY_SEG_STRICT(ss);
|
||||||
|
|
||||||
{
|
|
||||||
unsigned int tmpflags;
|
|
||||||
|
|
||||||
err |= __get_user(tmpflags, &sc->flags);
|
err |= __get_user(tmpflags, &sc->flags);
|
||||||
regs->flags = (regs->flags & ~FIX_EFLAGS) |
|
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
|
||||||
(tmpflags & FIX_EFLAGS);
|
|
||||||
regs->orig_ax = -1; /* disable syscall checks */
|
regs->orig_ax = -1; /* disable syscall checks */
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
void __user *buf;
|
|
||||||
|
|
||||||
err |= __get_user(buf, &sc->fpstate);
|
err |= __get_user(buf, &sc->fpstate);
|
||||||
err |= restore_i387_xstate(buf);
|
err |= restore_i387_xstate(buf);
|
||||||
}
|
|
||||||
|
|
||||||
err |= __get_user(*pax, &sc->ax);
|
err |= __get_user(*pax, &sc->ax);
|
||||||
return err;
|
return err;
|
||||||
|
@ -482,24 +479,34 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||||
/*
|
/*
|
||||||
* OK, we're invoking a handler:
|
* OK, we're invoking a handler:
|
||||||
*/
|
*/
|
||||||
|
static int signr_convert(int sig)
|
||||||
|
{
|
||||||
|
struct thread_info *info = current_thread_info();
|
||||||
|
|
||||||
|
if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32)
|
||||||
|
return info->exec_domain->signal_invmap[sig];
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define is_ia32 1
|
||||||
|
#define ia32_setup_frame __setup_frame
|
||||||
|
#define ia32_setup_rt_frame __setup_rt_frame
|
||||||
|
|
||||||
static int
|
static int
|
||||||
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||||
sigset_t *set, struct pt_regs *regs)
|
sigset_t *set, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
int usig = signr_convert(sig);
|
||||||
int ret;
|
int ret;
|
||||||
int usig;
|
|
||||||
|
|
||||||
usig = current_thread_info()->exec_domain
|
|
||||||
&& current_thread_info()->exec_domain->signal_invmap
|
|
||||||
&& sig < 32
|
|
||||||
? current_thread_info()->exec_domain->signal_invmap[sig]
|
|
||||||
: sig;
|
|
||||||
|
|
||||||
/* Set up the stack frame */
|
/* Set up the stack frame */
|
||||||
|
if (is_ia32) {
|
||||||
if (ka->sa.sa_flags & SA_SIGINFO)
|
if (ka->sa.sa_flags & SA_SIGINFO)
|
||||||
ret = __setup_rt_frame(usig, ka, info, set, regs);
|
ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
|
||||||
else
|
else
|
||||||
ret = __setup_frame(usig, ka, set, regs);
|
ret = ia32_setup_frame(usig, ka, set, regs);
|
||||||
|
} else
|
||||||
|
ret = __setup_rt_frame(sig, ka, info, set, regs);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
force_sigsegv(sig, current);
|
force_sigsegv(sig, current);
|
||||||
|
@ -550,6 +557,15 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
/*
|
||||||
|
* This has nothing to do with segment registers,
|
||||||
|
* despite the name. This magic affects uaccess.h
|
||||||
|
* macros' behavior. Reset it to the normal setting.
|
||||||
|
*/
|
||||||
|
set_fs(USER_DS);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the direction flag as per the ABI for function entry.
|
* Clear the direction flag as per the ABI for function entry.
|
||||||
*/
|
*/
|
||||||
|
@ -663,6 +679,12 @@ static void do_signal(struct pt_regs *regs)
|
||||||
void
|
void
|
||||||
do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
|
do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
|
||||||
{
|
{
|
||||||
|
#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
|
||||||
|
/* notify userspace of pending MCEs */
|
||||||
|
if (thread_info_flags & _TIF_MCE_NOTIFY)
|
||||||
|
mce_notify_user();
|
||||||
|
#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
|
||||||
|
|
||||||
/* deal with pending signal delivery */
|
/* deal with pending signal delivery */
|
||||||
if (thread_info_flags & _TIF_SIGPENDING)
|
if (thread_info_flags & _TIF_SIGPENDING)
|
||||||
do_signal(regs);
|
do_signal(regs);
|
||||||
|
@ -672,7 +694,9 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
|
||||||
tracehook_notify_resume(regs);
|
tracehook_notify_resume(regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
clear_thread_flag(TIF_IRET);
|
clear_thread_flag(TIF_IRET);
|
||||||
|
#endif /* CONFIG_X86_32 */
|
||||||
}
|
}
|
||||||
|
|
||||||
void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
|
void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
|
||||||
|
|
|
@ -52,6 +52,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
|
||||||
return do_sigaltstack(uss, uoss, regs->sp);
|
return do_sigaltstack(uss, uoss, regs->sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define COPY(x) { \
|
||||||
|
err |= __get_user(regs->x, &sc->x); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COPY_SEG_STRICT(seg) { \
|
||||||
|
unsigned short tmp; \
|
||||||
|
err |= __get_user(tmp, &sc->seg); \
|
||||||
|
regs->seg = tmp | 3; \
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do a signal return; undo the signal stack.
|
* Do a signal return; undo the signal stack.
|
||||||
*/
|
*/
|
||||||
|
@ -59,13 +69,13 @@ static int
|
||||||
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
||||||
unsigned long *pax)
|
unsigned long *pax)
|
||||||
{
|
{
|
||||||
|
void __user *buf;
|
||||||
|
unsigned int tmpflags;
|
||||||
unsigned int err = 0;
|
unsigned int err = 0;
|
||||||
|
|
||||||
/* Always make any pending restarted system calls return -EINTR */
|
/* Always make any pending restarted system calls return -EINTR */
|
||||||
current_thread_info()->restart_block.fn = do_no_restart_syscall;
|
current_thread_info()->restart_block.fn = do_no_restart_syscall;
|
||||||
|
|
||||||
#define COPY(x) (err |= __get_user(regs->x, &sc->x))
|
|
||||||
|
|
||||||
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
|
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
|
||||||
COPY(dx); COPY(cx); COPY(ip);
|
COPY(dx); COPY(cx); COPY(ip);
|
||||||
COPY(r8);
|
COPY(r8);
|
||||||
|
@ -80,25 +90,14 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
||||||
/* Kernel saves and restores only the CS segment register on signals,
|
/* Kernel saves and restores only the CS segment register on signals,
|
||||||
* which is the bare minimum needed to allow mixed 32/64-bit code.
|
* which is the bare minimum needed to allow mixed 32/64-bit code.
|
||||||
* App's signal handler can save/restore other segments if needed. */
|
* App's signal handler can save/restore other segments if needed. */
|
||||||
{
|
COPY_SEG_STRICT(cs);
|
||||||
unsigned cs;
|
|
||||||
err |= __get_user(cs, &sc->cs);
|
|
||||||
regs->cs = cs | 3; /* Force into user mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
unsigned int tmpflags;
|
|
||||||
err |= __get_user(tmpflags, &sc->flags);
|
err |= __get_user(tmpflags, &sc->flags);
|
||||||
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
|
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
|
||||||
regs->orig_ax = -1; /* disable syscall checks */
|
regs->orig_ax = -1; /* disable syscall checks */
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
void __user *buf;
|
|
||||||
|
|
||||||
err |= __get_user(buf, &sc->fpstate);
|
err |= __get_user(buf, &sc->fpstate);
|
||||||
err |= restore_i387_xstate(buf);
|
err |= restore_i387_xstate(buf);
|
||||||
}
|
|
||||||
|
|
||||||
err |= __get_user(*pax, &sc->ax);
|
err |= __get_user(*pax, &sc->ax);
|
||||||
return err;
|
return err;
|
||||||
|
@ -281,20 +280,31 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||||
/*
|
/*
|
||||||
* OK, we're invoking a handler
|
* OK, we're invoking a handler
|
||||||
*/
|
*/
|
||||||
|
static int signr_convert(int sig)
|
||||||
|
{
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_IA32_EMULATION
|
||||||
|
#define is_ia32 test_thread_flag(TIF_IA32)
|
||||||
|
#else
|
||||||
|
#define is_ia32 0
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||||
sigset_t *set, struct pt_regs *regs)
|
sigset_t *set, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
int usig = signr_convert(sig);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
#ifdef CONFIG_IA32_EMULATION
|
/* Set up the stack frame */
|
||||||
if (test_thread_flag(TIF_IA32)) {
|
if (is_ia32) {
|
||||||
if (ka->sa.sa_flags & SA_SIGINFO)
|
if (ka->sa.sa_flags & SA_SIGINFO)
|
||||||
ret = ia32_setup_rt_frame(sig, ka, info, set, regs);
|
ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
|
||||||
else
|
else
|
||||||
ret = ia32_setup_frame(sig, ka, set, regs);
|
ret = ia32_setup_frame(usig, ka, set, regs);
|
||||||
} else
|
} else
|
||||||
#endif
|
|
||||||
ret = __setup_rt_frame(sig, ka, info, set, regs);
|
ret = __setup_rt_frame(sig, ka, info, set, regs);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -346,12 +356,14 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
/*
|
/*
|
||||||
* This has nothing to do with segment registers,
|
* This has nothing to do with segment registers,
|
||||||
* despite the name. This magic affects uaccess.h
|
* despite the name. This magic affects uaccess.h
|
||||||
* macros' behavior. Reset it to the normal setting.
|
* macros' behavior. Reset it to the normal setting.
|
||||||
*/
|
*/
|
||||||
set_fs(USER_DS);
|
set_fs(USER_DS);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the direction flag as per the ABI for function entry.
|
* Clear the direction flag as per the ABI for function entry.
|
||||||
|
@ -410,7 +422,8 @@ static void do_signal(struct pt_regs *regs)
|
||||||
|
|
||||||
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
||||||
if (signr > 0) {
|
if (signr > 0) {
|
||||||
/* Re-enable any watchpoints before delivering the
|
/*
|
||||||
|
* Re-enable any watchpoints before delivering the
|
||||||
* signal to user space. The processor register will
|
* signal to user space. The processor register will
|
||||||
* have been cleared if the watchpoint triggered
|
* have been cleared if the watchpoint triggered
|
||||||
* inside the kernel.
|
* inside the kernel.
|
||||||
|
@ -441,6 +454,7 @@ static void do_signal(struct pt_regs *regs)
|
||||||
regs->ax = regs->orig_ax;
|
regs->ax = regs->orig_ax;
|
||||||
regs->ip -= 2;
|
regs->ip -= 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -ERESTART_RESTARTBLOCK:
|
case -ERESTART_RESTARTBLOCK:
|
||||||
regs->ax = NR_restart_syscall;
|
regs->ax = NR_restart_syscall;
|
||||||
regs->ip -= 2;
|
regs->ip -= 2;
|
||||||
|
@ -458,14 +472,18 @@ static void do_signal(struct pt_regs *regs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_notify_resume(struct pt_regs *regs, void *unused,
|
/*
|
||||||
__u32 thread_info_flags)
|
* notification of userspace execution resumption
|
||||||
|
* - triggered by the TIF_WORK_MASK flags
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_X86_MCE
|
#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
|
||||||
/* notify userspace of pending MCEs */
|
/* notify userspace of pending MCEs */
|
||||||
if (thread_info_flags & _TIF_MCE_NOTIFY)
|
if (thread_info_flags & _TIF_MCE_NOTIFY)
|
||||||
mce_notify_user();
|
mce_notify_user();
|
||||||
#endif /* CONFIG_X86_MCE */
|
#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
|
||||||
|
|
||||||
/* deal with pending signal delivery */
|
/* deal with pending signal delivery */
|
||||||
if (thread_info_flags & _TIF_SIGPENDING)
|
if (thread_info_flags & _TIF_SIGPENDING)
|
||||||
|
@ -475,6 +493,10 @@ void do_notify_resume(struct pt_regs *regs, void *unused,
|
||||||
clear_thread_flag(TIF_NOTIFY_RESUME);
|
clear_thread_flag(TIF_NOTIFY_RESUME);
|
||||||
tracehook_notify_resume(regs);
|
tracehook_notify_resume(regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
|
clear_thread_flag(TIF_IRET);
|
||||||
|
#endif /* CONFIG_X86_32 */
|
||||||
}
|
}
|
||||||
|
|
||||||
void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
|
void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue