Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc: sparc: Allow handling signals when stack is corrupted.
This commit is contained in:
commit
2983573e49
@ -45,6 +45,19 @@ typedef struct {
|
|||||||
int si_mask;
|
int si_mask;
|
||||||
} __siginfo32_t;
|
} __siginfo32_t;
|
||||||
|
|
||||||
|
#define __SIGC_MAXWIN 7
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned long locals[8];
|
||||||
|
unsigned long ins[8];
|
||||||
|
} __siginfo_reg_window;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int wsaved;
|
||||||
|
__siginfo_reg_window reg_window[__SIGC_MAXWIN];
|
||||||
|
unsigned long rwbuf_stkptrs[__SIGC_MAXWIN];
|
||||||
|
} __siginfo_rwin_t;
|
||||||
|
|
||||||
#ifdef CONFIG_SPARC64
|
#ifdef CONFIG_SPARC64
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int si_float_regs [64];
|
unsigned int si_float_regs [64];
|
||||||
@ -73,6 +86,7 @@ struct sigcontext {
|
|||||||
unsigned long ss_size;
|
unsigned long ss_size;
|
||||||
} sigc_stack;
|
} sigc_stack;
|
||||||
unsigned long sigc_mask;
|
unsigned long sigc_mask;
|
||||||
|
__siginfo_rwin_t * sigc_rwin_save;
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -32,6 +32,7 @@ obj-$(CONFIG_SPARC32) += sun4m_irq.o sun4c_irq.o sun4d_irq.o
|
|||||||
|
|
||||||
obj-y += process_$(BITS).o
|
obj-y += process_$(BITS).o
|
||||||
obj-y += signal_$(BITS).o
|
obj-y += signal_$(BITS).o
|
||||||
|
obj-y += sigutil_$(BITS).o
|
||||||
obj-$(CONFIG_SPARC32) += ioport.o
|
obj-$(CONFIG_SPARC32) += ioport.o
|
||||||
obj-y += setup_$(BITS).o
|
obj-y += setup_$(BITS).o
|
||||||
obj-y += idprom.o
|
obj-y += idprom.o
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
#include <asm/visasm.h>
|
#include <asm/visasm.h>
|
||||||
#include <asm/compat_signal.h>
|
#include <asm/compat_signal.h>
|
||||||
|
|
||||||
|
#include "sigutil.h"
|
||||||
|
|
||||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||||
|
|
||||||
/* This magic should be in g_upper[0] for all upper parts
|
/* This magic should be in g_upper[0] for all upper parts
|
||||||
@ -44,14 +46,14 @@ typedef struct {
|
|||||||
struct signal_frame32 {
|
struct signal_frame32 {
|
||||||
struct sparc_stackf32 ss;
|
struct sparc_stackf32 ss;
|
||||||
__siginfo32_t info;
|
__siginfo32_t info;
|
||||||
/* __siginfo_fpu32_t * */ u32 fpu_save;
|
/* __siginfo_fpu_t * */ u32 fpu_save;
|
||||||
unsigned int insns[2];
|
unsigned int insns[2];
|
||||||
unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
|
unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
|
||||||
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
|
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
|
||||||
/* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
|
/* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
|
||||||
siginfo_extra_v8plus_t v8plus;
|
siginfo_extra_v8plus_t v8plus;
|
||||||
__siginfo_fpu_t fpu_state;
|
/* __siginfo_rwin_t * */u32 rwin_save;
|
||||||
};
|
} __attribute__((aligned(8)));
|
||||||
|
|
||||||
typedef struct compat_siginfo{
|
typedef struct compat_siginfo{
|
||||||
int si_signo;
|
int si_signo;
|
||||||
@ -110,18 +112,14 @@ struct rt_signal_frame32 {
|
|||||||
compat_siginfo_t info;
|
compat_siginfo_t info;
|
||||||
struct pt_regs32 regs;
|
struct pt_regs32 regs;
|
||||||
compat_sigset_t mask;
|
compat_sigset_t mask;
|
||||||
/* __siginfo_fpu32_t * */ u32 fpu_save;
|
/* __siginfo_fpu_t * */ u32 fpu_save;
|
||||||
unsigned int insns[2];
|
unsigned int insns[2];
|
||||||
stack_t32 stack;
|
stack_t32 stack;
|
||||||
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
|
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
|
||||||
/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
|
/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
|
||||||
siginfo_extra_v8plus_t v8plus;
|
siginfo_extra_v8plus_t v8plus;
|
||||||
__siginfo_fpu_t fpu_state;
|
/* __siginfo_rwin_t * */u32 rwin_save;
|
||||||
};
|
} __attribute__((aligned(8)));
|
||||||
|
|
||||||
/* Align macros */
|
|
||||||
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame32) + 15) & (~15)))
|
|
||||||
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 15) & (~15)))
|
|
||||||
|
|
||||||
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
|
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
|
||||||
{
|
{
|
||||||
@ -192,30 +190,13 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
|
||||||
{
|
|
||||||
unsigned long *fpregs = current_thread_info()->fpregs;
|
|
||||||
unsigned long fprs;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = __get_user(fprs, &fpu->si_fprs);
|
|
||||||
fprs_write(0);
|
|
||||||
regs->tstate &= ~TSTATE_PEF;
|
|
||||||
if (fprs & FPRS_DL)
|
|
||||||
err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
|
|
||||||
if (fprs & FPRS_DU)
|
|
||||||
err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
|
|
||||||
err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
|
||||||
err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
|
||||||
current_thread_info()->fpsaved[0] |= fprs;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_sigreturn32(struct pt_regs *regs)
|
void do_sigreturn32(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct signal_frame32 __user *sf;
|
struct signal_frame32 __user *sf;
|
||||||
|
compat_uptr_t fpu_save;
|
||||||
|
compat_uptr_t rwin_save;
|
||||||
unsigned int psr;
|
unsigned int psr;
|
||||||
unsigned pc, npc, fpu_save;
|
unsigned pc, npc;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
unsigned seta[_COMPAT_NSIG_WORDS];
|
unsigned seta[_COMPAT_NSIG_WORDS];
|
||||||
int err, i;
|
int err, i;
|
||||||
@ -273,8 +254,13 @@ void do_sigreturn32(struct pt_regs *regs)
|
|||||||
pt_regs_clear_syscall(regs);
|
pt_regs_clear_syscall(regs);
|
||||||
|
|
||||||
err |= __get_user(fpu_save, &sf->fpu_save);
|
err |= __get_user(fpu_save, &sf->fpu_save);
|
||||||
if (fpu_save)
|
if (!err && fpu_save)
|
||||||
err |= restore_fpu_state32(regs, &sf->fpu_state);
|
err |= restore_fpu_state(regs, compat_ptr(fpu_save));
|
||||||
|
err |= __get_user(rwin_save, &sf->rwin_save);
|
||||||
|
if (!err && rwin_save) {
|
||||||
|
if (restore_rwin_state(compat_ptr(rwin_save)))
|
||||||
|
goto segv;
|
||||||
|
}
|
||||||
err |= __get_user(seta[0], &sf->info.si_mask);
|
err |= __get_user(seta[0], &sf->info.si_mask);
|
||||||
err |= copy_from_user(seta+1, &sf->extramask,
|
err |= copy_from_user(seta+1, &sf->extramask,
|
||||||
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
|
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
|
||||||
@ -300,7 +286,9 @@ segv:
|
|||||||
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
|
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct rt_signal_frame32 __user *sf;
|
struct rt_signal_frame32 __user *sf;
|
||||||
unsigned int psr, pc, npc, fpu_save, u_ss_sp;
|
unsigned int psr, pc, npc, u_ss_sp;
|
||||||
|
compat_uptr_t fpu_save;
|
||||||
|
compat_uptr_t rwin_save;
|
||||||
mm_segment_t old_fs;
|
mm_segment_t old_fs;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
compat_sigset_t seta;
|
compat_sigset_t seta;
|
||||||
@ -359,8 +347,8 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
|
|||||||
pt_regs_clear_syscall(regs);
|
pt_regs_clear_syscall(regs);
|
||||||
|
|
||||||
err |= __get_user(fpu_save, &sf->fpu_save);
|
err |= __get_user(fpu_save, &sf->fpu_save);
|
||||||
if (fpu_save)
|
if (!err && fpu_save)
|
||||||
err |= restore_fpu_state32(regs, &sf->fpu_state);
|
err |= restore_fpu_state(regs, compat_ptr(fpu_save));
|
||||||
err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
|
err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
|
||||||
err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
|
err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
|
||||||
st.ss_sp = compat_ptr(u_ss_sp);
|
st.ss_sp = compat_ptr(u_ss_sp);
|
||||||
@ -376,6 +364,12 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
|
|||||||
do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
|
do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
|
||||||
set_fs(old_fs);
|
set_fs(old_fs);
|
||||||
|
|
||||||
|
err |= __get_user(rwin_save, &sf->rwin_save);
|
||||||
|
if (!err && rwin_save) {
|
||||||
|
if (restore_rwin_state(compat_ptr(rwin_save)))
|
||||||
|
goto segv;
|
||||||
|
}
|
||||||
|
|
||||||
switch (_NSIG_WORDS) {
|
switch (_NSIG_WORDS) {
|
||||||
case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
|
case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
|
||||||
case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
|
case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
|
||||||
@ -433,26 +427,6 @@ static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, uns
|
|||||||
return (void __user *) sp;
|
return (void __user *) sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
|
||||||
{
|
|
||||||
unsigned long *fpregs = current_thread_info()->fpregs;
|
|
||||||
unsigned long fprs;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
fprs = current_thread_info()->fpsaved[0];
|
|
||||||
if (fprs & FPRS_DL)
|
|
||||||
err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
|
|
||||||
(sizeof(unsigned int) * 32));
|
|
||||||
if (fprs & FPRS_DU)
|
|
||||||
err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
|
|
||||||
(sizeof(unsigned int) * 32));
|
|
||||||
err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
|
||||||
err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
|
||||||
err |= __put_user(fprs, &fpu->si_fprs);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The I-cache flush instruction only works in the primary ASI, which
|
/* The I-cache flush instruction only works in the primary ASI, which
|
||||||
* right now is the nucleus, aka. kernel space.
|
* right now is the nucleus, aka. kernel space.
|
||||||
*
|
*
|
||||||
@ -515,18 +489,23 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
int signo, sigset_t *oldset)
|
int signo, sigset_t *oldset)
|
||||||
{
|
{
|
||||||
struct signal_frame32 __user *sf;
|
struct signal_frame32 __user *sf;
|
||||||
|
int i, err, wsaved;
|
||||||
|
void __user *tail;
|
||||||
int sigframe_size;
|
int sigframe_size;
|
||||||
u32 psr;
|
u32 psr;
|
||||||
int i, err;
|
|
||||||
unsigned int seta[_COMPAT_NSIG_WORDS];
|
unsigned int seta[_COMPAT_NSIG_WORDS];
|
||||||
|
|
||||||
/* 1. Make sure everything is clean */
|
/* 1. Make sure everything is clean */
|
||||||
synchronize_user_stack();
|
synchronize_user_stack();
|
||||||
save_and_clear_fpu();
|
save_and_clear_fpu();
|
||||||
|
|
||||||
sigframe_size = SF_ALIGNEDSZ;
|
wsaved = get_thread_wsaved();
|
||||||
if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
|
|
||||||
sigframe_size -= sizeof(__siginfo_fpu_t);
|
sigframe_size = sizeof(*sf);
|
||||||
|
if (current_thread_info()->fpsaved[0] & FPRS_FEF)
|
||||||
|
sigframe_size += sizeof(__siginfo_fpu_t);
|
||||||
|
if (wsaved)
|
||||||
|
sigframe_size += sizeof(__siginfo_rwin_t);
|
||||||
|
|
||||||
sf = (struct signal_frame32 __user *)
|
sf = (struct signal_frame32 __user *)
|
||||||
get_sigframe(&ka->sa, regs, sigframe_size);
|
get_sigframe(&ka->sa, regs, sigframe_size);
|
||||||
@ -534,8 +513,7 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
if (invalid_frame_pointer(sf, sigframe_size))
|
if (invalid_frame_pointer(sf, sigframe_size))
|
||||||
goto sigill;
|
goto sigill;
|
||||||
|
|
||||||
if (get_thread_wsaved() != 0)
|
tail = (sf + 1);
|
||||||
goto sigill;
|
|
||||||
|
|
||||||
/* 2. Save the current process state */
|
/* 2. Save the current process state */
|
||||||
if (test_thread_flag(TIF_32BIT)) {
|
if (test_thread_flag(TIF_32BIT)) {
|
||||||
@ -560,11 +538,22 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
&sf->v8plus.asi);
|
&sf->v8plus.asi);
|
||||||
|
|
||||||
if (psr & PSR_EF) {
|
if (psr & PSR_EF) {
|
||||||
err |= save_fpu_state32(regs, &sf->fpu_state);
|
__siginfo_fpu_t __user *fp = tail;
|
||||||
err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
|
tail += sizeof(*fp);
|
||||||
|
err |= save_fpu_state(regs, fp);
|
||||||
|
err |= __put_user((u64)fp, &sf->fpu_save);
|
||||||
} else {
|
} else {
|
||||||
err |= __put_user(0, &sf->fpu_save);
|
err |= __put_user(0, &sf->fpu_save);
|
||||||
}
|
}
|
||||||
|
if (wsaved) {
|
||||||
|
__siginfo_rwin_t __user *rwp = tail;
|
||||||
|
tail += sizeof(*rwp);
|
||||||
|
err |= save_rwin_state(wsaved, rwp);
|
||||||
|
err |= __put_user((u64)rwp, &sf->rwin_save);
|
||||||
|
set_thread_wsaved(0);
|
||||||
|
} else {
|
||||||
|
err |= __put_user(0, &sf->rwin_save);
|
||||||
|
}
|
||||||
|
|
||||||
switch (_NSIG_WORDS) {
|
switch (_NSIG_WORDS) {
|
||||||
case 4: seta[7] = (oldset->sig[3] >> 32);
|
case 4: seta[7] = (oldset->sig[3] >> 32);
|
||||||
@ -580,10 +569,21 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
err |= __copy_to_user(sf->extramask, seta + 1,
|
err |= __copy_to_user(sf->extramask, seta + 1,
|
||||||
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
|
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
|
||||||
|
|
||||||
err |= copy_in_user((u32 __user *)sf,
|
if (!wsaved) {
|
||||||
(u32 __user *)(regs->u_regs[UREG_FP]),
|
err |= copy_in_user((u32 __user *)sf,
|
||||||
sizeof(struct reg_window32));
|
(u32 __user *)(regs->u_regs[UREG_FP]),
|
||||||
|
sizeof(struct reg_window32));
|
||||||
|
} else {
|
||||||
|
struct reg_window *rp;
|
||||||
|
|
||||||
|
rp = ¤t_thread_info()->reg_window[wsaved - 1];
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
|
||||||
|
for (i = 0; i < 6; i++)
|
||||||
|
err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
|
||||||
|
err |= __put_user(rp->ins[6], &sf->ss.fp);
|
||||||
|
err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
|
||||||
|
}
|
||||||
if (err)
|
if (err)
|
||||||
goto sigsegv;
|
goto sigsegv;
|
||||||
|
|
||||||
@ -613,7 +613,6 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
|
err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
|
||||||
if (err)
|
if (err)
|
||||||
goto sigsegv;
|
goto sigsegv;
|
||||||
|
|
||||||
flush_signal_insns(address);
|
flush_signal_insns(address);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -632,18 +631,23 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
siginfo_t *info)
|
siginfo_t *info)
|
||||||
{
|
{
|
||||||
struct rt_signal_frame32 __user *sf;
|
struct rt_signal_frame32 __user *sf;
|
||||||
|
int i, err, wsaved;
|
||||||
|
void __user *tail;
|
||||||
int sigframe_size;
|
int sigframe_size;
|
||||||
u32 psr;
|
u32 psr;
|
||||||
int i, err;
|
|
||||||
compat_sigset_t seta;
|
compat_sigset_t seta;
|
||||||
|
|
||||||
/* 1. Make sure everything is clean */
|
/* 1. Make sure everything is clean */
|
||||||
synchronize_user_stack();
|
synchronize_user_stack();
|
||||||
save_and_clear_fpu();
|
save_and_clear_fpu();
|
||||||
|
|
||||||
sigframe_size = RT_ALIGNEDSZ;
|
wsaved = get_thread_wsaved();
|
||||||
if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
|
|
||||||
sigframe_size -= sizeof(__siginfo_fpu_t);
|
sigframe_size = sizeof(*sf);
|
||||||
|
if (current_thread_info()->fpsaved[0] & FPRS_FEF)
|
||||||
|
sigframe_size += sizeof(__siginfo_fpu_t);
|
||||||
|
if (wsaved)
|
||||||
|
sigframe_size += sizeof(__siginfo_rwin_t);
|
||||||
|
|
||||||
sf = (struct rt_signal_frame32 __user *)
|
sf = (struct rt_signal_frame32 __user *)
|
||||||
get_sigframe(&ka->sa, regs, sigframe_size);
|
get_sigframe(&ka->sa, regs, sigframe_size);
|
||||||
@ -651,8 +655,7 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
if (invalid_frame_pointer(sf, sigframe_size))
|
if (invalid_frame_pointer(sf, sigframe_size))
|
||||||
goto sigill;
|
goto sigill;
|
||||||
|
|
||||||
if (get_thread_wsaved() != 0)
|
tail = (sf + 1);
|
||||||
goto sigill;
|
|
||||||
|
|
||||||
/* 2. Save the current process state */
|
/* 2. Save the current process state */
|
||||||
if (test_thread_flag(TIF_32BIT)) {
|
if (test_thread_flag(TIF_32BIT)) {
|
||||||
@ -677,11 +680,22 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
&sf->v8plus.asi);
|
&sf->v8plus.asi);
|
||||||
|
|
||||||
if (psr & PSR_EF) {
|
if (psr & PSR_EF) {
|
||||||
err |= save_fpu_state32(regs, &sf->fpu_state);
|
__siginfo_fpu_t __user *fp = tail;
|
||||||
err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
|
tail += sizeof(*fp);
|
||||||
|
err |= save_fpu_state(regs, fp);
|
||||||
|
err |= __put_user((u64)fp, &sf->fpu_save);
|
||||||
} else {
|
} else {
|
||||||
err |= __put_user(0, &sf->fpu_save);
|
err |= __put_user(0, &sf->fpu_save);
|
||||||
}
|
}
|
||||||
|
if (wsaved) {
|
||||||
|
__siginfo_rwin_t __user *rwp = tail;
|
||||||
|
tail += sizeof(*rwp);
|
||||||
|
err |= save_rwin_state(wsaved, rwp);
|
||||||
|
err |= __put_user((u64)rwp, &sf->rwin_save);
|
||||||
|
set_thread_wsaved(0);
|
||||||
|
} else {
|
||||||
|
err |= __put_user(0, &sf->rwin_save);
|
||||||
|
}
|
||||||
|
|
||||||
/* Update the siginfo structure. */
|
/* Update the siginfo structure. */
|
||||||
err |= copy_siginfo_to_user32(&sf->info, info);
|
err |= copy_siginfo_to_user32(&sf->info, info);
|
||||||
@ -703,9 +717,21 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
}
|
}
|
||||||
err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
|
err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
|
||||||
|
|
||||||
err |= copy_in_user((u32 __user *)sf,
|
if (!wsaved) {
|
||||||
(u32 __user *)(regs->u_regs[UREG_FP]),
|
err |= copy_in_user((u32 __user *)sf,
|
||||||
sizeof(struct reg_window32));
|
(u32 __user *)(regs->u_regs[UREG_FP]),
|
||||||
|
sizeof(struct reg_window32));
|
||||||
|
} else {
|
||||||
|
struct reg_window *rp;
|
||||||
|
|
||||||
|
rp = ¤t_thread_info()->reg_window[wsaved - 1];
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
|
||||||
|
for (i = 0; i < 6; i++)
|
||||||
|
err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
|
||||||
|
err |= __put_user(rp->ins[6], &sf->ss.fp);
|
||||||
|
err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
|
||||||
|
}
|
||||||
if (err)
|
if (err)
|
||||||
goto sigsegv;
|
goto sigsegv;
|
||||||
|
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/cacheflush.h> /* flush_sig_insns */
|
#include <asm/cacheflush.h> /* flush_sig_insns */
|
||||||
|
|
||||||
|
#include "sigutil.h"
|
||||||
|
|
||||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||||
|
|
||||||
extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
|
extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
|
||||||
@ -39,8 +41,8 @@ struct signal_frame {
|
|||||||
unsigned long insns[2] __attribute__ ((aligned (8)));
|
unsigned long insns[2] __attribute__ ((aligned (8)));
|
||||||
unsigned int extramask[_NSIG_WORDS - 1];
|
unsigned int extramask[_NSIG_WORDS - 1];
|
||||||
unsigned int extra_size; /* Should be 0 */
|
unsigned int extra_size; /* Should be 0 */
|
||||||
__siginfo_fpu_t fpu_state;
|
__siginfo_rwin_t __user *rwin_save;
|
||||||
};
|
} __attribute__((aligned(8)));
|
||||||
|
|
||||||
struct rt_signal_frame {
|
struct rt_signal_frame {
|
||||||
struct sparc_stackf ss;
|
struct sparc_stackf ss;
|
||||||
@ -51,8 +53,8 @@ struct rt_signal_frame {
|
|||||||
unsigned int insns[2];
|
unsigned int insns[2];
|
||||||
stack_t stack;
|
stack_t stack;
|
||||||
unsigned int extra_size; /* Should be 0 */
|
unsigned int extra_size; /* Should be 0 */
|
||||||
__siginfo_fpu_t fpu_state;
|
__siginfo_rwin_t __user *rwin_save;
|
||||||
};
|
} __attribute__((aligned(8)));
|
||||||
|
|
||||||
/* Align macros */
|
/* Align macros */
|
||||||
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
|
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
|
||||||
@ -79,43 +81,13 @@ asmlinkage int sys_sigsuspend(old_sigset_t set)
|
|||||||
return _sigpause_common(set);
|
return _sigpause_common(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
|
||||||
restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
if (test_tsk_thread_flag(current, TIF_USEDFPU))
|
|
||||||
regs->psr &= ~PSR_EF;
|
|
||||||
#else
|
|
||||||
if (current == last_task_used_math) {
|
|
||||||
last_task_used_math = NULL;
|
|
||||||
regs->psr &= ~PSR_EF;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
set_used_math();
|
|
||||||
clear_tsk_thread_flag(current, TIF_USEDFPU);
|
|
||||||
|
|
||||||
if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0],
|
|
||||||
(sizeof(unsigned long) * 32));
|
|
||||||
err |= __get_user(current->thread.fsr, &fpu->si_fsr);
|
|
||||||
err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
|
|
||||||
if (current->thread.fpqdepth != 0)
|
|
||||||
err |= __copy_from_user(¤t->thread.fpqueue[0],
|
|
||||||
&fpu->si_fpqueue[0],
|
|
||||||
((sizeof(unsigned long) +
|
|
||||||
(sizeof(unsigned long *)))*16));
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
asmlinkage void do_sigreturn(struct pt_regs *regs)
|
asmlinkage void do_sigreturn(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct signal_frame __user *sf;
|
struct signal_frame __user *sf;
|
||||||
unsigned long up_psr, pc, npc;
|
unsigned long up_psr, pc, npc;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
__siginfo_fpu_t __user *fpu_save;
|
__siginfo_fpu_t __user *fpu_save;
|
||||||
|
__siginfo_rwin_t __user *rwin_save;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* Always make any pending restarted system calls return -EINTR */
|
/* Always make any pending restarted system calls return -EINTR */
|
||||||
@ -150,9 +122,11 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
|
|||||||
pt_regs_clear_syscall(regs);
|
pt_regs_clear_syscall(regs);
|
||||||
|
|
||||||
err |= __get_user(fpu_save, &sf->fpu_save);
|
err |= __get_user(fpu_save, &sf->fpu_save);
|
||||||
|
|
||||||
if (fpu_save)
|
if (fpu_save)
|
||||||
err |= restore_fpu_state(regs, fpu_save);
|
err |= restore_fpu_state(regs, fpu_save);
|
||||||
|
err |= __get_user(rwin_save, &sf->rwin_save);
|
||||||
|
if (rwin_save)
|
||||||
|
err |= restore_rwin_state(rwin_save);
|
||||||
|
|
||||||
/* This is pretty much atomic, no amount locking would prevent
|
/* This is pretty much atomic, no amount locking would prevent
|
||||||
* the races which exist anyways.
|
* the races which exist anyways.
|
||||||
@ -180,6 +154,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
|
|||||||
struct rt_signal_frame __user *sf;
|
struct rt_signal_frame __user *sf;
|
||||||
unsigned int psr, pc, npc;
|
unsigned int psr, pc, npc;
|
||||||
__siginfo_fpu_t __user *fpu_save;
|
__siginfo_fpu_t __user *fpu_save;
|
||||||
|
__siginfo_rwin_t __user *rwin_save;
|
||||||
mm_segment_t old_fs;
|
mm_segment_t old_fs;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
stack_t st;
|
stack_t st;
|
||||||
@ -207,8 +182,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
|
|||||||
pt_regs_clear_syscall(regs);
|
pt_regs_clear_syscall(regs);
|
||||||
|
|
||||||
err |= __get_user(fpu_save, &sf->fpu_save);
|
err |= __get_user(fpu_save, &sf->fpu_save);
|
||||||
|
if (!err && fpu_save)
|
||||||
if (fpu_save)
|
|
||||||
err |= restore_fpu_state(regs, fpu_save);
|
err |= restore_fpu_state(regs, fpu_save);
|
||||||
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
|
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
|
||||||
|
|
||||||
@ -228,6 +202,12 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
|
|||||||
do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
|
do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
|
||||||
set_fs(old_fs);
|
set_fs(old_fs);
|
||||||
|
|
||||||
|
err |= __get_user(rwin_save, &sf->rwin_save);
|
||||||
|
if (!err && rwin_save) {
|
||||||
|
if (restore_rwin_state(rwin_save))
|
||||||
|
goto segv;
|
||||||
|
}
|
||||||
|
|
||||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
spin_lock_irq(¤t->sighand->siglock);
|
||||||
current->blocked = set;
|
current->blocked = set;
|
||||||
@ -280,53 +260,23 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re
|
|||||||
return (void __user *) sp;
|
return (void __user *) sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
|
||||||
save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
|
|
||||||
put_psr(get_psr() | PSR_EF);
|
|
||||||
fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
|
|
||||||
¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
|
|
||||||
regs->psr &= ~(PSR_EF);
|
|
||||||
clear_tsk_thread_flag(current, TIF_USEDFPU);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (current == last_task_used_math) {
|
|
||||||
put_psr(get_psr() | PSR_EF);
|
|
||||||
fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
|
|
||||||
¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
|
|
||||||
last_task_used_math = NULL;
|
|
||||||
regs->psr &= ~(PSR_EF);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
err |= __copy_to_user(&fpu->si_float_regs[0],
|
|
||||||
¤t->thread.float_regs[0],
|
|
||||||
(sizeof(unsigned long) * 32));
|
|
||||||
err |= __put_user(current->thread.fsr, &fpu->si_fsr);
|
|
||||||
err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
|
|
||||||
if (current->thread.fpqdepth != 0)
|
|
||||||
err |= __copy_to_user(&fpu->si_fpqueue[0],
|
|
||||||
¤t->thread.fpqueue[0],
|
|
||||||
((sizeof(unsigned long) +
|
|
||||||
(sizeof(unsigned long *)))*16));
|
|
||||||
clear_used_math();
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
||||||
int signo, sigset_t *oldset)
|
int signo, sigset_t *oldset)
|
||||||
{
|
{
|
||||||
struct signal_frame __user *sf;
|
struct signal_frame __user *sf;
|
||||||
int sigframe_size, err;
|
int sigframe_size, err, wsaved;
|
||||||
|
void __user *tail;
|
||||||
|
|
||||||
/* 1. Make sure everything is clean */
|
/* 1. Make sure everything is clean */
|
||||||
synchronize_user_stack();
|
synchronize_user_stack();
|
||||||
|
|
||||||
sigframe_size = SF_ALIGNEDSZ;
|
wsaved = current_thread_info()->w_saved;
|
||||||
if (!used_math())
|
|
||||||
sigframe_size -= sizeof(__siginfo_fpu_t);
|
sigframe_size = sizeof(*sf);
|
||||||
|
if (used_math())
|
||||||
|
sigframe_size += sizeof(__siginfo_fpu_t);
|
||||||
|
if (wsaved)
|
||||||
|
sigframe_size += sizeof(__siginfo_rwin_t);
|
||||||
|
|
||||||
sf = (struct signal_frame __user *)
|
sf = (struct signal_frame __user *)
|
||||||
get_sigframe(&ka->sa, regs, sigframe_size);
|
get_sigframe(&ka->sa, regs, sigframe_size);
|
||||||
@ -334,8 +284,7 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
if (invalid_frame_pointer(sf, sigframe_size))
|
if (invalid_frame_pointer(sf, sigframe_size))
|
||||||
goto sigill_and_return;
|
goto sigill_and_return;
|
||||||
|
|
||||||
if (current_thread_info()->w_saved != 0)
|
tail = sf + 1;
|
||||||
goto sigill_and_return;
|
|
||||||
|
|
||||||
/* 2. Save the current process state */
|
/* 2. Save the current process state */
|
||||||
err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
|
err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
|
||||||
@ -343,17 +292,34 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
err |= __put_user(0, &sf->extra_size);
|
err |= __put_user(0, &sf->extra_size);
|
||||||
|
|
||||||
if (used_math()) {
|
if (used_math()) {
|
||||||
err |= save_fpu_state(regs, &sf->fpu_state);
|
__siginfo_fpu_t __user *fp = tail;
|
||||||
err |= __put_user(&sf->fpu_state, &sf->fpu_save);
|
tail += sizeof(*fp);
|
||||||
|
err |= save_fpu_state(regs, fp);
|
||||||
|
err |= __put_user(fp, &sf->fpu_save);
|
||||||
} else {
|
} else {
|
||||||
err |= __put_user(0, &sf->fpu_save);
|
err |= __put_user(0, &sf->fpu_save);
|
||||||
}
|
}
|
||||||
|
if (wsaved) {
|
||||||
|
__siginfo_rwin_t __user *rwp = tail;
|
||||||
|
tail += sizeof(*rwp);
|
||||||
|
err |= save_rwin_state(wsaved, rwp);
|
||||||
|
err |= __put_user(rwp, &sf->rwin_save);
|
||||||
|
} else {
|
||||||
|
err |= __put_user(0, &sf->rwin_save);
|
||||||
|
}
|
||||||
|
|
||||||
err |= __put_user(oldset->sig[0], &sf->info.si_mask);
|
err |= __put_user(oldset->sig[0], &sf->info.si_mask);
|
||||||
err |= __copy_to_user(sf->extramask, &oldset->sig[1],
|
err |= __copy_to_user(sf->extramask, &oldset->sig[1],
|
||||||
(_NSIG_WORDS - 1) * sizeof(unsigned int));
|
(_NSIG_WORDS - 1) * sizeof(unsigned int));
|
||||||
err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
|
if (!wsaved) {
|
||||||
sizeof(struct reg_window32));
|
err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
|
||||||
|
sizeof(struct reg_window32));
|
||||||
|
} else {
|
||||||
|
struct reg_window32 *rp;
|
||||||
|
|
||||||
|
rp = ¤t_thread_info()->reg_window[wsaved - 1];
|
||||||
|
err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
|
||||||
|
}
|
||||||
if (err)
|
if (err)
|
||||||
goto sigsegv;
|
goto sigsegv;
|
||||||
|
|
||||||
@ -399,21 +365,24 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
int signo, sigset_t *oldset, siginfo_t *info)
|
int signo, sigset_t *oldset, siginfo_t *info)
|
||||||
{
|
{
|
||||||
struct rt_signal_frame __user *sf;
|
struct rt_signal_frame __user *sf;
|
||||||
int sigframe_size;
|
int sigframe_size, wsaved;
|
||||||
|
void __user *tail;
|
||||||
unsigned int psr;
|
unsigned int psr;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
synchronize_user_stack();
|
synchronize_user_stack();
|
||||||
sigframe_size = RT_ALIGNEDSZ;
|
wsaved = current_thread_info()->w_saved;
|
||||||
if (!used_math())
|
sigframe_size = sizeof(*sf);
|
||||||
sigframe_size -= sizeof(__siginfo_fpu_t);
|
if (used_math())
|
||||||
|
sigframe_size += sizeof(__siginfo_fpu_t);
|
||||||
|
if (wsaved)
|
||||||
|
sigframe_size += sizeof(__siginfo_rwin_t);
|
||||||
sf = (struct rt_signal_frame __user *)
|
sf = (struct rt_signal_frame __user *)
|
||||||
get_sigframe(&ka->sa, regs, sigframe_size);
|
get_sigframe(&ka->sa, regs, sigframe_size);
|
||||||
if (invalid_frame_pointer(sf, sigframe_size))
|
if (invalid_frame_pointer(sf, sigframe_size))
|
||||||
goto sigill;
|
goto sigill;
|
||||||
if (current_thread_info()->w_saved != 0)
|
|
||||||
goto sigill;
|
|
||||||
|
|
||||||
|
tail = sf + 1;
|
||||||
err = __put_user(regs->pc, &sf->regs.pc);
|
err = __put_user(regs->pc, &sf->regs.pc);
|
||||||
err |= __put_user(regs->npc, &sf->regs.npc);
|
err |= __put_user(regs->npc, &sf->regs.npc);
|
||||||
err |= __put_user(regs->y, &sf->regs.y);
|
err |= __put_user(regs->y, &sf->regs.y);
|
||||||
@ -425,11 +394,21 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
err |= __put_user(0, &sf->extra_size);
|
err |= __put_user(0, &sf->extra_size);
|
||||||
|
|
||||||
if (psr & PSR_EF) {
|
if (psr & PSR_EF) {
|
||||||
err |= save_fpu_state(regs, &sf->fpu_state);
|
__siginfo_fpu_t *fp = tail;
|
||||||
err |= __put_user(&sf->fpu_state, &sf->fpu_save);
|
tail += sizeof(*fp);
|
||||||
|
err |= save_fpu_state(regs, fp);
|
||||||
|
err |= __put_user(fp, &sf->fpu_save);
|
||||||
} else {
|
} else {
|
||||||
err |= __put_user(0, &sf->fpu_save);
|
err |= __put_user(0, &sf->fpu_save);
|
||||||
}
|
}
|
||||||
|
if (wsaved) {
|
||||||
|
__siginfo_rwin_t *rwp = tail;
|
||||||
|
tail += sizeof(*rwp);
|
||||||
|
err |= save_rwin_state(wsaved, rwp);
|
||||||
|
err |= __put_user(rwp, &sf->rwin_save);
|
||||||
|
} else {
|
||||||
|
err |= __put_user(0, &sf->rwin_save);
|
||||||
|
}
|
||||||
err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
|
err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
|
||||||
|
|
||||||
/* Setup sigaltstack */
|
/* Setup sigaltstack */
|
||||||
@ -437,8 +416,15 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
|
err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
|
||||||
err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
|
err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
|
||||||
|
|
||||||
err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
|
if (!wsaved) {
|
||||||
sizeof(struct reg_window32));
|
err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
|
||||||
|
sizeof(struct reg_window32));
|
||||||
|
} else {
|
||||||
|
struct reg_window32 *rp;
|
||||||
|
|
||||||
|
rp = ¤t_thread_info()->reg_window[wsaved - 1];
|
||||||
|
err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
|
||||||
|
}
|
||||||
|
|
||||||
err |= copy_siginfo_to_user(&sf->info, info);
|
err |= copy_siginfo_to_user(&sf->info, info);
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include "entry.h"
|
#include "entry.h"
|
||||||
#include "systbls.h"
|
#include "systbls.h"
|
||||||
|
#include "sigutil.h"
|
||||||
|
|
||||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||||
|
|
||||||
@ -236,7 +237,7 @@ struct rt_signal_frame {
|
|||||||
__siginfo_fpu_t __user *fpu_save;
|
__siginfo_fpu_t __user *fpu_save;
|
||||||
stack_t stack;
|
stack_t stack;
|
||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
__siginfo_fpu_t fpu_state;
|
__siginfo_rwin_t *rwin_save;
|
||||||
};
|
};
|
||||||
|
|
||||||
static long _sigpause_common(old_sigset_t set)
|
static long _sigpause_common(old_sigset_t set)
|
||||||
@ -266,33 +267,12 @@ asmlinkage long sys_sigsuspend(old_sigset_t set)
|
|||||||
return _sigpause_common(set);
|
return _sigpause_common(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
|
||||||
restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
|
||||||
{
|
|
||||||
unsigned long *fpregs = current_thread_info()->fpregs;
|
|
||||||
unsigned long fprs;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = __get_user(fprs, &fpu->si_fprs);
|
|
||||||
fprs_write(0);
|
|
||||||
regs->tstate &= ~TSTATE_PEF;
|
|
||||||
if (fprs & FPRS_DL)
|
|
||||||
err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
|
|
||||||
(sizeof(unsigned int) * 32));
|
|
||||||
if (fprs & FPRS_DU)
|
|
||||||
err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
|
|
||||||
(sizeof(unsigned int) * 32));
|
|
||||||
err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
|
||||||
err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
|
||||||
current_thread_info()->fpsaved[0] |= fprs;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_rt_sigreturn(struct pt_regs *regs)
|
void do_rt_sigreturn(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct rt_signal_frame __user *sf;
|
struct rt_signal_frame __user *sf;
|
||||||
unsigned long tpc, tnpc, tstate;
|
unsigned long tpc, tnpc, tstate;
|
||||||
__siginfo_fpu_t __user *fpu_save;
|
__siginfo_fpu_t __user *fpu_save;
|
||||||
|
__siginfo_rwin_t __user *rwin_save;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@ -325,8 +305,8 @@ void do_rt_sigreturn(struct pt_regs *regs)
|
|||||||
regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC));
|
regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC));
|
||||||
|
|
||||||
err |= __get_user(fpu_save, &sf->fpu_save);
|
err |= __get_user(fpu_save, &sf->fpu_save);
|
||||||
if (fpu_save)
|
if (!err && fpu_save)
|
||||||
err |= restore_fpu_state(regs, &sf->fpu_state);
|
err |= restore_fpu_state(regs, fpu_save);
|
||||||
|
|
||||||
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
|
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
|
||||||
err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf);
|
err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf);
|
||||||
@ -334,6 +314,12 @@ void do_rt_sigreturn(struct pt_regs *regs)
|
|||||||
if (err)
|
if (err)
|
||||||
goto segv;
|
goto segv;
|
||||||
|
|
||||||
|
err |= __get_user(rwin_save, &sf->rwin_save);
|
||||||
|
if (!err && rwin_save) {
|
||||||
|
if (restore_rwin_state(rwin_save))
|
||||||
|
goto segv;
|
||||||
|
}
|
||||||
|
|
||||||
regs->tpc = tpc;
|
regs->tpc = tpc;
|
||||||
regs->tnpc = tnpc;
|
regs->tnpc = tnpc;
|
||||||
|
|
||||||
@ -351,34 +337,13 @@ segv:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Checks if the fp is valid */
|
/* Checks if the fp is valid */
|
||||||
static int invalid_frame_pointer(void __user *fp, int fplen)
|
static int invalid_frame_pointer(void __user *fp)
|
||||||
{
|
{
|
||||||
if (((unsigned long) fp) & 15)
|
if (((unsigned long) fp) & 15)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
|
||||||
save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
|
||||||
{
|
|
||||||
unsigned long *fpregs = current_thread_info()->fpregs;
|
|
||||||
unsigned long fprs;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
fprs = current_thread_info()->fpsaved[0];
|
|
||||||
if (fprs & FPRS_DL)
|
|
||||||
err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
|
|
||||||
(sizeof(unsigned int) * 32));
|
|
||||||
if (fprs & FPRS_DU)
|
|
||||||
err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
|
|
||||||
(sizeof(unsigned int) * 32));
|
|
||||||
err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
|
||||||
err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
|
||||||
err |= __put_user(fprs, &fpu->si_fprs);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
|
static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
|
||||||
{
|
{
|
||||||
unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
|
unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
|
||||||
@ -414,34 +379,48 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
int signo, sigset_t *oldset, siginfo_t *info)
|
int signo, sigset_t *oldset, siginfo_t *info)
|
||||||
{
|
{
|
||||||
struct rt_signal_frame __user *sf;
|
struct rt_signal_frame __user *sf;
|
||||||
int sigframe_size, err;
|
int wsaved, err, sf_size;
|
||||||
|
void __user *tail;
|
||||||
|
|
||||||
/* 1. Make sure everything is clean */
|
/* 1. Make sure everything is clean */
|
||||||
synchronize_user_stack();
|
synchronize_user_stack();
|
||||||
save_and_clear_fpu();
|
save_and_clear_fpu();
|
||||||
|
|
||||||
sigframe_size = sizeof(struct rt_signal_frame);
|
wsaved = get_thread_wsaved();
|
||||||
if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
|
|
||||||
sigframe_size -= sizeof(__siginfo_fpu_t);
|
|
||||||
|
|
||||||
|
sf_size = sizeof(struct rt_signal_frame);
|
||||||
|
if (current_thread_info()->fpsaved[0] & FPRS_FEF)
|
||||||
|
sf_size += sizeof(__siginfo_fpu_t);
|
||||||
|
if (wsaved)
|
||||||
|
sf_size += sizeof(__siginfo_rwin_t);
|
||||||
sf = (struct rt_signal_frame __user *)
|
sf = (struct rt_signal_frame __user *)
|
||||||
get_sigframe(ka, regs, sigframe_size);
|
get_sigframe(ka, regs, sf_size);
|
||||||
|
|
||||||
if (invalid_frame_pointer (sf, sigframe_size))
|
if (invalid_frame_pointer (sf))
|
||||||
goto sigill;
|
goto sigill;
|
||||||
|
|
||||||
if (get_thread_wsaved() != 0)
|
tail = (sf + 1);
|
||||||
goto sigill;
|
|
||||||
|
|
||||||
/* 2. Save the current process state */
|
/* 2. Save the current process state */
|
||||||
err = copy_to_user(&sf->regs, regs, sizeof (*regs));
|
err = copy_to_user(&sf->regs, regs, sizeof (*regs));
|
||||||
|
|
||||||
if (current_thread_info()->fpsaved[0] & FPRS_FEF) {
|
if (current_thread_info()->fpsaved[0] & FPRS_FEF) {
|
||||||
err |= save_fpu_state(regs, &sf->fpu_state);
|
__siginfo_fpu_t __user *fpu_save = tail;
|
||||||
err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
|
tail += sizeof(__siginfo_fpu_t);
|
||||||
|
err |= save_fpu_state(regs, fpu_save);
|
||||||
|
err |= __put_user((u64)fpu_save, &sf->fpu_save);
|
||||||
} else {
|
} else {
|
||||||
err |= __put_user(0, &sf->fpu_save);
|
err |= __put_user(0, &sf->fpu_save);
|
||||||
}
|
}
|
||||||
|
if (wsaved) {
|
||||||
|
__siginfo_rwin_t __user *rwin_save = tail;
|
||||||
|
tail += sizeof(__siginfo_rwin_t);
|
||||||
|
err |= save_rwin_state(wsaved, rwin_save);
|
||||||
|
err |= __put_user((u64)rwin_save, &sf->rwin_save);
|
||||||
|
set_thread_wsaved(0);
|
||||||
|
} else {
|
||||||
|
err |= __put_user(0, &sf->rwin_save);
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup sigaltstack */
|
/* Setup sigaltstack */
|
||||||
err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
|
err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
|
||||||
@ -450,10 +429,17 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
|||||||
|
|
||||||
err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
|
err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
|
||||||
|
|
||||||
err |= copy_in_user((u64 __user *)sf,
|
if (!wsaved) {
|
||||||
(u64 __user *)(regs->u_regs[UREG_FP]+STACK_BIAS),
|
err |= copy_in_user((u64 __user *)sf,
|
||||||
sizeof(struct reg_window));
|
(u64 __user *)(regs->u_regs[UREG_FP] +
|
||||||
|
STACK_BIAS),
|
||||||
|
sizeof(struct reg_window));
|
||||||
|
} else {
|
||||||
|
struct reg_window *rp;
|
||||||
|
|
||||||
|
rp = ¤t_thread_info()->reg_window[wsaved - 1];
|
||||||
|
err |= copy_to_user(sf, rp, sizeof(struct reg_window));
|
||||||
|
}
|
||||||
if (info)
|
if (info)
|
||||||
err |= copy_siginfo_to_user(&sf->info, info);
|
err |= copy_siginfo_to_user(&sf->info, info);
|
||||||
else {
|
else {
|
||||||
|
9
arch/sparc/kernel/sigutil.h
Normal file
9
arch/sparc/kernel/sigutil.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef _SIGUTIL_H
|
||||||
|
#define _SIGUTIL_H
|
||||||
|
|
||||||
|
int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
|
||||||
|
int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
|
||||||
|
int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin);
|
||||||
|
int restore_rwin_state(__siginfo_rwin_t __user *rp);
|
||||||
|
|
||||||
|
#endif /* _SIGUTIL_H */
|
120
arch/sparc/kernel/sigutil_32.c
Normal file
120
arch/sparc/kernel/sigutil_32.c
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/thread_info.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
|
||||||
|
#include <asm/sigcontext.h>
|
||||||
|
#include <asm/fpumacro.h>
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
|
||||||
|
#include "sigutil.h"
|
||||||
|
|
||||||
|
int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
|
||||||
|
put_psr(get_psr() | PSR_EF);
|
||||||
|
fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
|
||||||
|
¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
|
||||||
|
regs->psr &= ~(PSR_EF);
|
||||||
|
clear_tsk_thread_flag(current, TIF_USEDFPU);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (current == last_task_used_math) {
|
||||||
|
put_psr(get_psr() | PSR_EF);
|
||||||
|
fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
|
||||||
|
¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
|
||||||
|
last_task_used_math = NULL;
|
||||||
|
regs->psr &= ~(PSR_EF);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
err |= __copy_to_user(&fpu->si_float_regs[0],
|
||||||
|
¤t->thread.float_regs[0],
|
||||||
|
(sizeof(unsigned long) * 32));
|
||||||
|
err |= __put_user(current->thread.fsr, &fpu->si_fsr);
|
||||||
|
err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
|
||||||
|
if (current->thread.fpqdepth != 0)
|
||||||
|
err |= __copy_to_user(&fpu->si_fpqueue[0],
|
||||||
|
¤t->thread.fpqueue[0],
|
||||||
|
((sizeof(unsigned long) +
|
||||||
|
(sizeof(unsigned long *)))*16));
|
||||||
|
clear_used_math();
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
if (test_tsk_thread_flag(current, TIF_USEDFPU))
|
||||||
|
regs->psr &= ~PSR_EF;
|
||||||
|
#else
|
||||||
|
if (current == last_task_used_math) {
|
||||||
|
last_task_used_math = NULL;
|
||||||
|
regs->psr &= ~PSR_EF;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
set_used_math();
|
||||||
|
clear_tsk_thread_flag(current, TIF_USEDFPU);
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0],
|
||||||
|
(sizeof(unsigned long) * 32));
|
||||||
|
err |= __get_user(current->thread.fsr, &fpu->si_fsr);
|
||||||
|
err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
|
||||||
|
if (current->thread.fpqdepth != 0)
|
||||||
|
err |= __copy_from_user(¤t->thread.fpqueue[0],
|
||||||
|
&fpu->si_fpqueue[0],
|
||||||
|
((sizeof(unsigned long) +
|
||||||
|
(sizeof(unsigned long *)))*16));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
|
||||||
|
{
|
||||||
|
int i, err = __put_user(wsaved, &rwin->wsaved);
|
||||||
|
|
||||||
|
for (i = 0; i < wsaved; i++) {
|
||||||
|
struct reg_window32 *rp;
|
||||||
|
unsigned long fp;
|
||||||
|
|
||||||
|
rp = ¤t_thread_info()->reg_window[i];
|
||||||
|
fp = current_thread_info()->rwbuf_stkptrs[i];
|
||||||
|
err |= copy_to_user(&rwin->reg_window[i], rp,
|
||||||
|
sizeof(struct reg_window32));
|
||||||
|
err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int restore_rwin_state(__siginfo_rwin_t __user *rp)
|
||||||
|
{
|
||||||
|
struct thread_info *t = current_thread_info();
|
||||||
|
int i, wsaved, err;
|
||||||
|
|
||||||
|
__get_user(wsaved, &rp->wsaved);
|
||||||
|
if (wsaved > NSWINS)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
for (i = 0; i < wsaved; i++) {
|
||||||
|
err |= copy_from_user(&t->reg_window[i],
|
||||||
|
&rp->reg_window[i],
|
||||||
|
sizeof(struct reg_window32));
|
||||||
|
err |= __get_user(t->rwbuf_stkptrs[i],
|
||||||
|
&rp->rwbuf_stkptrs[i]);
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
t->w_saved = wsaved;
|
||||||
|
synchronize_user_stack();
|
||||||
|
if (t->w_saved)
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
93
arch/sparc/kernel/sigutil_64.c
Normal file
93
arch/sparc/kernel/sigutil_64.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/thread_info.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
#include <asm/sigcontext.h>
|
||||||
|
#include <asm/fpumacro.h>
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
|
||||||
|
#include "sigutil.h"
|
||||||
|
|
||||||
|
int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||||
|
{
|
||||||
|
unsigned long *fpregs = current_thread_info()->fpregs;
|
||||||
|
unsigned long fprs;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
fprs = current_thread_info()->fpsaved[0];
|
||||||
|
if (fprs & FPRS_DL)
|
||||||
|
err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
|
||||||
|
(sizeof(unsigned int) * 32));
|
||||||
|
if (fprs & FPRS_DU)
|
||||||
|
err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
|
||||||
|
(sizeof(unsigned int) * 32));
|
||||||
|
err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
||||||
|
err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
||||||
|
err |= __put_user(fprs, &fpu->si_fprs);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||||
|
{
|
||||||
|
unsigned long *fpregs = current_thread_info()->fpregs;
|
||||||
|
unsigned long fprs;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = __get_user(fprs, &fpu->si_fprs);
|
||||||
|
fprs_write(0);
|
||||||
|
regs->tstate &= ~TSTATE_PEF;
|
||||||
|
if (fprs & FPRS_DL)
|
||||||
|
err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
|
||||||
|
(sizeof(unsigned int) * 32));
|
||||||
|
if (fprs & FPRS_DU)
|
||||||
|
err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
|
||||||
|
(sizeof(unsigned int) * 32));
|
||||||
|
err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
||||||
|
err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
||||||
|
current_thread_info()->fpsaved[0] |= fprs;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
|
||||||
|
{
|
||||||
|
int i, err = __put_user(wsaved, &rwin->wsaved);
|
||||||
|
|
||||||
|
for (i = 0; i < wsaved; i++) {
|
||||||
|
struct reg_window *rp = ¤t_thread_info()->reg_window[i];
|
||||||
|
unsigned long fp = current_thread_info()->rwbuf_stkptrs[i];
|
||||||
|
|
||||||
|
err |= copy_to_user(&rwin->reg_window[i], rp,
|
||||||
|
sizeof(struct reg_window));
|
||||||
|
err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int restore_rwin_state(__siginfo_rwin_t __user *rp)
|
||||||
|
{
|
||||||
|
struct thread_info *t = current_thread_info();
|
||||||
|
int i, wsaved, err;
|
||||||
|
|
||||||
|
__get_user(wsaved, &rp->wsaved);
|
||||||
|
if (wsaved > NSWINS)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
for (i = 0; i < wsaved; i++) {
|
||||||
|
err |= copy_from_user(&t->reg_window[i],
|
||||||
|
&rp->reg_window[i],
|
||||||
|
sizeof(struct reg_window));
|
||||||
|
err |= __get_user(t->rwbuf_stkptrs[i],
|
||||||
|
&rp->rwbuf_stkptrs[i]);
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
set_thread_wsaved(wsaved);
|
||||||
|
synchronize_user_stack();
|
||||||
|
if (get_thread_wsaved())
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user