diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2011-08-30 14:49:51 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-08-30 14:49:51 -0700 |
commit | aa860198da73375bbdfa0be997b5d77352e098b6 (patch) | |
tree | f50c87b3682b96886a21da0bac8f61edf93987ca | |
parent | 42c4d8d501c0c167dab8d441366d59f2ff6104da (diff) | |
download | stable-queue-aa860198da73375bbdfa0be997b5d77352e098b6.tar.gz |
3.0 patches
7 files changed, 1382 insertions, 0 deletions
diff --git a/queue-3.0/series b/queue-3.0/series index f45ac717b9..4ce67dc173 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -37,3 +37,9 @@ pata_via-disable-atapi-dma-on-averatec-3200.patch atm-br2684-fix-oops-due-to-skb-dev-being-null.patch rt2x00-fix-crash-in-rt2800usb_write_tx_desc.patch rt2x00-fix-crash-in-rt2800usb_get_txwi.patch +sparc64-remove-unnecessary-macros-from-spinlock_64.h.patch +sparc32-unbreak-arch_write_unlock.patch +sparc-allow-handling-signals-when-stack-is-corrupted.patch +sparc64-set-have_c_recordmcount.patch +sparc-fix-array-bounds-error-setting-up-pcic-nmi-trap.patch +sparc32-sun4d-change-ipi-irq-level-to-prevent-collision.patch diff --git a/queue-3.0/sparc-allow-handling-signals-when-stack-is-corrupted.patch b/queue-3.0/sparc-allow-handling-signals-when-stack-is-corrupted.patch new file mode 100644 index 0000000000..82908c39ab --- /dev/null +++ b/queue-3.0/sparc-allow-handling-signals-when-stack-is-corrupted.patch @@ -0,0 +1,1157 @@ +From 5598473a5b40c47a8c5349dd2c2630797169cf1a Mon Sep 17 00:00:00 2001 +From: "David S. Miller" <davem@davemloft.net> +Date: Sat, 20 Aug 2011 17:14:54 -0700 +Subject: sparc: Allow handling signals when stack is corrupted. + +From: "David S. Miller" <davem@davemloft.net> + +commit 5598473a5b40c47a8c5349dd2c2630797169cf1a upstream. + +If we can't push the pending register windows onto the user's stack, +we disallow signal delivery even if the signal would be delivered on a +valid seperate signal stack. + +Add a register window save area in the signal frame, and store any +unsavable windows there. + +On sigreturn, if any windows are still queued up in the signal frame, +try to push them back onto the stack and if that fails we kill the +process immediately. + +This allows the debug/tst-longjmp_chk2 glibc test case to pass. + +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + arch/sparc/include/asm/sigcontext.h | 14 ++ + arch/sparc/kernel/Makefile | 1 + arch/sparc/kernel/signal32.c | 184 ++++++++++++++++++++---------------- + arch/sparc/kernel/signal_32.c | 172 +++++++++++++++------------------ + arch/sparc/kernel/signal_64.c | 108 +++++++++------------ + arch/sparc/kernel/sigutil.h | 9 + + arch/sparc/kernel/sigutil_32.c | 120 +++++++++++++++++++++++ + arch/sparc/kernel/sigutil_64.c | 93 ++++++++++++++++++ + 8 files changed, 468 insertions(+), 233 deletions(-) + +--- a/arch/sparc/include/asm/sigcontext.h ++++ b/arch/sparc/include/asm/sigcontext.h +@@ -45,6 +45,19 @@ typedef struct { + int si_mask; + } __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 + typedef struct { + unsigned int si_float_regs [64]; +@@ -73,6 +86,7 @@ struct sigcontext { + unsigned long ss_size; + } sigc_stack; + unsigned long sigc_mask; ++ __siginfo_rwin_t * sigc_rwin_save; + }; + + #else +--- a/arch/sparc/kernel/Makefile ++++ b/arch/sparc/kernel/Makefile +@@ -32,6 +32,7 @@ obj-$(CONFIG_SPARC32) += sun4m_irq.o s + + obj-y += process_$(BITS).o + obj-y += signal_$(BITS).o ++obj-y += sigutil_$(BITS).o + obj-$(CONFIG_SPARC32) += ioport.o + obj-y += setup_$(BITS).o + obj-y += idprom.o +--- a/arch/sparc/kernel/signal32.c ++++ b/arch/sparc/kernel/signal32.c +@@ -29,6 +29,8 @@ + #include <asm/visasm.h> + #include <asm/compat_signal.h> + ++#include "sigutil.h" ++ + #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + + /* This magic should be in g_upper[0] for all upper parts +@@ -44,14 +46,14 @@ typedef struct { + struct signal_frame32 { + struct sparc_stackf32 ss; + __siginfo32_t info; +- /* __siginfo_fpu32_t * */ u32 fpu_save; ++ /* __siginfo_fpu_t * */ u32 fpu_save; + unsigned int insns[2]; + unsigned int extramask[_COMPAT_NSIG_WORDS - 1]; + unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */ + /* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */ + siginfo_extra_v8plus_t v8plus; +- __siginfo_fpu_t fpu_state; +-}; ++ /* __siginfo_rwin_t * */u32 rwin_save; ++} __attribute__((aligned(8))); + + typedef struct compat_siginfo{ + int si_signo; +@@ -110,18 +112,14 @@ struct rt_signal_frame32 { + compat_siginfo_t info; + struct pt_regs32 regs; + compat_sigset_t mask; +- /* __siginfo_fpu32_t * */ u32 fpu_save; ++ /* __siginfo_fpu_t * */ u32 fpu_save; + unsigned int insns[2]; + stack_t32 stack; + unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */ + /* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */ + siginfo_extra_v8plus_t v8plus; +- __siginfo_fpu_t fpu_state; +-}; +- +-/* Align macros */ +-#define SF_ALIGNEDSZ (((sizeof(struct signal_frame32) + 15) & (~15))) +-#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 15) & (~15))) ++ /* __siginfo_rwin_t * */u32 rwin_save; ++} __attribute__((aligned(8))); + + int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) + { +@@ -192,30 +190,13 @@ int copy_siginfo_from_user32(siginfo_t * + 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) + { + struct signal_frame32 __user *sf; ++ compat_uptr_t fpu_save; ++ compat_uptr_t rwin_save; + unsigned int psr; +- unsigned pc, npc, fpu_save; ++ unsigned pc, npc; + sigset_t set; + unsigned seta[_COMPAT_NSIG_WORDS]; + int err, i; +@@ -273,8 +254,13 @@ void do_sigreturn32(struct pt_regs *regs + pt_regs_clear_syscall(regs); + + err |= __get_user(fpu_save, &sf->fpu_save); +- if (fpu_save) +- err |= restore_fpu_state32(regs, &sf->fpu_state); ++ if (!err && fpu_save) ++ 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 |= copy_from_user(seta+1, &sf->extramask, + (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int)); +@@ -300,7 +286,9 @@ segv: + asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) + { + 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; + sigset_t set; + compat_sigset_t seta; +@@ -359,8 +347,8 @@ asmlinkage void do_rt_sigreturn32(struct + pt_regs_clear_syscall(regs); + + err |= __get_user(fpu_save, &sf->fpu_save); +- if (fpu_save) +- err |= restore_fpu_state32(regs, &sf->fpu_state); ++ if (!err && fpu_save) ++ err |= restore_fpu_state(regs, compat_ptr(fpu_save)); + err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t)); + err |= __get_user(u_ss_sp, &sf->stack.ss_sp); + st.ss_sp = compat_ptr(u_ss_sp); +@@ -376,6 +364,12 @@ asmlinkage void do_rt_sigreturn32(struct + do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf); + 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) { + 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); +@@ -433,26 +427,6 @@ static void __user *get_sigframe(struct + 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 + * right now is the nucleus, aka. kernel space. + * +@@ -515,18 +489,23 @@ static int setup_frame32(struct k_sigact + int signo, sigset_t *oldset) + { + struct signal_frame32 __user *sf; ++ int i, err, wsaved; ++ void __user *tail; + int sigframe_size; + u32 psr; +- int i, err; + unsigned int seta[_COMPAT_NSIG_WORDS]; + + /* 1. Make sure everything is clean */ + synchronize_user_stack(); + save_and_clear_fpu(); + +- sigframe_size = SF_ALIGNEDSZ; +- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) +- sigframe_size -= sizeof(__siginfo_fpu_t); ++ wsaved = get_thread_wsaved(); ++ ++ 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 *) + get_sigframe(&ka->sa, regs, sigframe_size); +@@ -534,8 +513,7 @@ static int setup_frame32(struct k_sigact + if (invalid_frame_pointer(sf, sigframe_size)) + goto sigill; + +- if (get_thread_wsaved() != 0) +- goto sigill; ++ tail = (sf + 1); + + /* 2. Save the current process state */ + if (test_thread_flag(TIF_32BIT)) { +@@ -560,11 +538,22 @@ static int setup_frame32(struct k_sigact + &sf->v8plus.asi); + + if (psr & PSR_EF) { +- err |= save_fpu_state32(regs, &sf->fpu_state); +- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); ++ __siginfo_fpu_t __user *fp = tail; ++ tail += sizeof(*fp); ++ err |= save_fpu_state(regs, fp); ++ err |= __put_user((u64)fp, &sf->fpu_save); + } else { + 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) { + case 4: seta[7] = (oldset->sig[3] >> 32); +@@ -580,10 +569,21 @@ static int setup_frame32(struct k_sigact + err |= __copy_to_user(sf->extramask, seta + 1, + (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int)); + +- err |= copy_in_user((u32 __user *)sf, +- (u32 __user *)(regs->u_regs[UREG_FP]), +- sizeof(struct reg_window32)); +- ++ if (!wsaved) { ++ err |= copy_in_user((u32 __user *)sf, ++ (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) + goto sigsegv; + +@@ -613,7 +613,6 @@ static int setup_frame32(struct k_sigact + err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/ + if (err) + goto sigsegv; +- + flush_signal_insns(address); + } + return 0; +@@ -632,18 +631,23 @@ static int setup_rt_frame32(struct k_sig + siginfo_t *info) + { + struct rt_signal_frame32 __user *sf; ++ int i, err, wsaved; ++ void __user *tail; + int sigframe_size; + u32 psr; +- int i, err; + compat_sigset_t seta; + + /* 1. Make sure everything is clean */ + synchronize_user_stack(); + save_and_clear_fpu(); + +- sigframe_size = RT_ALIGNEDSZ; +- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) +- sigframe_size -= sizeof(__siginfo_fpu_t); ++ wsaved = get_thread_wsaved(); ++ ++ 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 *) + get_sigframe(&ka->sa, regs, sigframe_size); +@@ -651,8 +655,7 @@ static int setup_rt_frame32(struct k_sig + if (invalid_frame_pointer(sf, sigframe_size)) + goto sigill; + +- if (get_thread_wsaved() != 0) +- goto sigill; ++ tail = (sf + 1); + + /* 2. Save the current process state */ + if (test_thread_flag(TIF_32BIT)) { +@@ -677,11 +680,22 @@ static int setup_rt_frame32(struct k_sig + &sf->v8plus.asi); + + if (psr & PSR_EF) { +- err |= save_fpu_state32(regs, &sf->fpu_state); +- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); ++ __siginfo_fpu_t __user *fp = tail; ++ tail += sizeof(*fp); ++ err |= save_fpu_state(regs, fp); ++ err |= __put_user((u64)fp, &sf->fpu_save); + } else { + 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. */ + err |= copy_siginfo_to_user32(&sf->info, info); +@@ -703,9 +717,21 @@ static int setup_rt_frame32(struct k_sig + } + err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t)); + +- err |= copy_in_user((u32 __user *)sf, +- (u32 __user *)(regs->u_regs[UREG_FP]), +- sizeof(struct reg_window32)); ++ if (!wsaved) { ++ err |= copy_in_user((u32 __user *)sf, ++ (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) + goto sigsegv; + +--- a/arch/sparc/kernel/signal_32.c ++++ b/arch/sparc/kernel/signal_32.c +@@ -26,6 +26,8 @@ + #include <asm/pgtable.h> + #include <asm/cacheflush.h> /* flush_sig_insns */ + ++#include "sigutil.h" ++ + #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + + extern void fpsave(unsigned long *fpregs, unsigned long *fsr, +@@ -39,8 +41,8 @@ struct signal_frame { + unsigned long insns[2] __attribute__ ((aligned (8))); + unsigned int extramask[_NSIG_WORDS - 1]; + 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 sparc_stackf ss; +@@ -51,8 +53,8 @@ struct rt_signal_frame { + unsigned int insns[2]; + stack_t stack; + unsigned int extra_size; /* Should be 0 */ +- __siginfo_fpu_t fpu_state; +-}; ++ __siginfo_rwin_t __user *rwin_save; ++} __attribute__((aligned(8))); + + /* Align macros */ + #define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7))) +@@ -79,43 +81,13 @@ asmlinkage int sys_sigsuspend(old_sigset + 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) + { + struct signal_frame __user *sf; + unsigned long up_psr, pc, npc; + sigset_t set; + __siginfo_fpu_t __user *fpu_save; ++ __siginfo_rwin_t __user *rwin_save; + int err; + + /* Always make any pending restarted system calls return -EINTR */ +@@ -150,9 +122,11 @@ asmlinkage void do_sigreturn(struct pt_r + pt_regs_clear_syscall(regs); + + err |= __get_user(fpu_save, &sf->fpu_save); +- + if (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 + * the races which exist anyways. +@@ -180,6 +154,7 @@ asmlinkage void do_rt_sigreturn(struct p + struct rt_signal_frame __user *sf; + unsigned int psr, pc, npc; + __siginfo_fpu_t __user *fpu_save; ++ __siginfo_rwin_t __user *rwin_save; + mm_segment_t old_fs; + sigset_t set; + stack_t st; +@@ -207,8 +182,7 @@ asmlinkage void do_rt_sigreturn(struct p + pt_regs_clear_syscall(regs); + + err |= __get_user(fpu_save, &sf->fpu_save); +- +- if (fpu_save) ++ if (!err && fpu_save) + err |= restore_fpu_state(regs, fpu_save); + err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); + +@@ -228,6 +202,12 @@ asmlinkage void do_rt_sigreturn(struct p + do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf); + 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); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; +@@ -280,53 +260,23 @@ static inline void __user *get_sigframe( + 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, + int signo, sigset_t *oldset) + { + struct signal_frame __user *sf; +- int sigframe_size, err; ++ int sigframe_size, err, wsaved; ++ void __user *tail; + + /* 1. Make sure everything is clean */ + synchronize_user_stack(); + +- sigframe_size = SF_ALIGNEDSZ; +- if (!used_math()) +- sigframe_size -= sizeof(__siginfo_fpu_t); ++ wsaved = current_thread_info()->w_saved; ++ ++ 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 *) + get_sigframe(&ka->sa, regs, sigframe_size); +@@ -334,8 +284,7 @@ static int setup_frame(struct k_sigactio + if (invalid_frame_pointer(sf, sigframe_size)) + goto sigill_and_return; + +- if (current_thread_info()->w_saved != 0) +- goto sigill_and_return; ++ tail = sf + 1; + + /* 2. Save the current process state */ + err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs)); +@@ -343,17 +292,34 @@ static int setup_frame(struct k_sigactio + err |= __put_user(0, &sf->extra_size); + + if (used_math()) { +- err |= save_fpu_state(regs, &sf->fpu_state); +- err |= __put_user(&sf->fpu_state, &sf->fpu_save); ++ __siginfo_fpu_t __user *fp = tail; ++ tail += sizeof(*fp); ++ err |= save_fpu_state(regs, fp); ++ err |= __put_user(fp, &sf->fpu_save); + } else { + 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 |= __copy_to_user(sf->extramask, &oldset->sig[1], + (_NSIG_WORDS - 1) * sizeof(unsigned int)); +- err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], +- sizeof(struct reg_window32)); ++ if (!wsaved) { ++ 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) + goto sigsegv; + +@@ -399,21 +365,24 @@ static int setup_rt_frame(struct k_sigac + int signo, sigset_t *oldset, siginfo_t *info) + { + struct rt_signal_frame __user *sf; +- int sigframe_size; ++ int sigframe_size, wsaved; ++ void __user *tail; + unsigned int psr; + int err; + + synchronize_user_stack(); +- sigframe_size = RT_ALIGNEDSZ; +- if (!used_math()) +- sigframe_size -= sizeof(__siginfo_fpu_t); ++ wsaved = current_thread_info()->w_saved; ++ sigframe_size = sizeof(*sf); ++ if (used_math()) ++ sigframe_size += sizeof(__siginfo_fpu_t); ++ if (wsaved) ++ sigframe_size += sizeof(__siginfo_rwin_t); + sf = (struct rt_signal_frame __user *) + get_sigframe(&ka->sa, regs, sigframe_size); + if (invalid_frame_pointer(sf, sigframe_size)) + 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->npc, &sf->regs.npc); + err |= __put_user(regs->y, &sf->regs.y); +@@ -425,11 +394,21 @@ static int setup_rt_frame(struct k_sigac + err |= __put_user(0, &sf->extra_size); + + if (psr & PSR_EF) { +- err |= save_fpu_state(regs, &sf->fpu_state); +- err |= __put_user(&sf->fpu_state, &sf->fpu_save); ++ __siginfo_fpu_t *fp = tail; ++ tail += sizeof(*fp); ++ err |= save_fpu_state(regs, fp); ++ err |= __put_user(fp, &sf->fpu_save); + } else { + 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)); + + /* Setup sigaltstack */ +@@ -437,8 +416,15 @@ static int setup_rt_frame(struct k_sigac + 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 |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], +- sizeof(struct reg_window32)); ++ if (!wsaved) { ++ 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); + +--- a/arch/sparc/kernel/signal_64.c ++++ b/arch/sparc/kernel/signal_64.c +@@ -34,6 +34,7 @@ + + #include "entry.h" + #include "systbls.h" ++#include "sigutil.h" + + #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +@@ -236,7 +237,7 @@ struct rt_signal_frame { + __siginfo_fpu_t __user *fpu_save; + stack_t stack; + sigset_t mask; +- __siginfo_fpu_t fpu_state; ++ __siginfo_rwin_t *rwin_save; + }; + + static long _sigpause_common(old_sigset_t set) +@@ -266,33 +267,12 @@ asmlinkage long sys_sigsuspend(old_sigse + 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) + { + struct rt_signal_frame __user *sf; + unsigned long tpc, tnpc, tstate; + __siginfo_fpu_t __user *fpu_save; ++ __siginfo_rwin_t __user *rwin_save; + sigset_t set; + int err; + +@@ -325,8 +305,8 @@ void do_rt_sigreturn(struct pt_regs *reg + regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC)); + + err |= __get_user(fpu_save, &sf->fpu_save); +- if (fpu_save) +- err |= restore_fpu_state(regs, &sf->fpu_state); ++ if (!err && fpu_save) ++ err |= restore_fpu_state(regs, fpu_save); + + err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); + err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf); +@@ -334,6 +314,12 @@ void do_rt_sigreturn(struct pt_regs *reg + if (err) + 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->tnpc = tnpc; + +@@ -351,34 +337,13 @@ segv: + } + + /* 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) + return 1; + 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) + { + unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS; +@@ -414,34 +379,48 @@ setup_rt_frame(struct k_sigaction *ka, s + int signo, sigset_t *oldset, siginfo_t *info) + { + struct rt_signal_frame __user *sf; +- int sigframe_size, err; ++ int wsaved, err, sf_size; ++ void __user *tail; + + /* 1. Make sure everything is clean */ + synchronize_user_stack(); + save_and_clear_fpu(); + +- sigframe_size = sizeof(struct rt_signal_frame); +- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) +- sigframe_size -= sizeof(__siginfo_fpu_t); ++ wsaved = get_thread_wsaved(); + ++ 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 *) +- get_sigframe(ka, regs, sigframe_size); +- +- if (invalid_frame_pointer (sf, sigframe_size)) +- goto sigill; ++ get_sigframe(ka, regs, sf_size); + +- if (get_thread_wsaved() != 0) ++ if (invalid_frame_pointer (sf)) + goto sigill; + ++ tail = (sf + 1); ++ + /* 2. Save the current process state */ + err = copy_to_user(&sf->regs, regs, sizeof (*regs)); + + if (current_thread_info()->fpsaved[0] & FPRS_FEF) { +- err |= save_fpu_state(regs, &sf->fpu_state); +- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); ++ __siginfo_fpu_t __user *fpu_save = tail; ++ tail += sizeof(__siginfo_fpu_t); ++ err |= save_fpu_state(regs, fpu_save); ++ err |= __put_user((u64)fpu_save, &sf->fpu_save); + } else { + 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 */ + err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); +@@ -450,10 +429,17 @@ setup_rt_frame(struct k_sigaction *ka, s + + err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); + +- err |= copy_in_user((u64 __user *)sf, +- (u64 __user *)(regs->u_regs[UREG_FP]+STACK_BIAS), +- sizeof(struct reg_window)); ++ if (!wsaved) { ++ err |= copy_in_user((u64 __user *)sf, ++ (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) + err |= copy_siginfo_to_user(&sf->info, info); + else { +--- /dev/null ++++ b/arch/sparc/kernel/sigutil.h +@@ -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 */ +--- /dev/null ++++ b/arch/sparc/kernel/sigutil_32.c +@@ -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; ++ ++} +--- /dev/null ++++ b/arch/sparc/kernel/sigutil_64.c +@@ -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; ++} diff --git a/queue-3.0/sparc-fix-array-bounds-error-setting-up-pcic-nmi-trap.patch b/queue-3.0/sparc-fix-array-bounds-error-setting-up-pcic-nmi-trap.patch new file mode 100644 index 0000000000..bcabab844a --- /dev/null +++ b/queue-3.0/sparc-fix-array-bounds-error-setting-up-pcic-nmi-trap.patch @@ -0,0 +1,48 @@ +From 4a0342ca8e8150bd47e7118a76e300692a1b6b7b Mon Sep 17 00:00:00 2001 +From: Ian Campbell <Ian.Campbell@citrix.com> +Date: Wed, 17 Aug 2011 22:14:57 +0000 +Subject: sparc: fix array bounds error setting up PCIC NMI trap + +From: Ian Campbell <Ian.Campbell@citrix.com> + +commit 4a0342ca8e8150bd47e7118a76e300692a1b6b7b upstream. + + CC arch/sparc/kernel/pcic.o +arch/sparc/kernel/pcic.c: In function 'pcic_probe': +arch/sparc/kernel/pcic.c:359:33: error: array subscript is above array bounds [-Werror=array-bounds] +arch/sparc/kernel/pcic.c:359:8: error: array subscript is above array bounds [-Werror=array-bounds] +arch/sparc/kernel/pcic.c:360:33: error: array subscript is above array bounds [-Werror=array-bounds] +arch/sparc/kernel/pcic.c:360:8: error: array subscript is above array bounds [-Werror=array-bounds] +arch/sparc/kernel/pcic.c:361:33: error: array subscript is above array bounds [-Werror=array-bounds] +arch/sparc/kernel/pcic.c:361:8: error: array subscript is above array bounds [-Werror=array-bounds] +cc1: all warnings being treated as errors + +I'm not particularly familiar with sparc but t_nmi (defined in head_32.S via +the TRAP_ENTRY macro) and pcic_nmi_trap_patch (defined in entry.S) both appear +to be 4 instructions long and I presume from the usage that instructions are +int sized. + +Signed-off-by: Ian Campbell <ian.campbell@citrix.com> +Cc: "David S. Miller" <davem@davemloft.net> +Cc: sparclinux@vger.kernel.org +Reviewed-by: Sam Ravnborg <sam@ravnborg.org> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + arch/sparc/kernel/pcic.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/sparc/kernel/pcic.c ++++ b/arch/sparc/kernel/pcic.c +@@ -352,8 +352,8 @@ int __init pcic_probe(void) + strcpy(pbm->prom_name, namebuf); + + { +- extern volatile int t_nmi[1]; +- extern int pcic_nmi_trap_patch[1]; ++ extern volatile int t_nmi[4]; ++ extern int pcic_nmi_trap_patch[4]; + + t_nmi[0] = pcic_nmi_trap_patch[0]; + t_nmi[1] = pcic_nmi_trap_patch[1]; diff --git a/queue-3.0/sparc32-sun4d-change-ipi-irq-level-to-prevent-collision.patch b/queue-3.0/sparc32-sun4d-change-ipi-irq-level-to-prevent-collision.patch new file mode 100644 index 0000000000..e61ccddfc6 --- /dev/null +++ b/queue-3.0/sparc32-sun4d-change-ipi-irq-level-to-prevent-collision.patch @@ -0,0 +1,41 @@ +From 38f7f8f05e8239e9871f7e1c4b0a842080e85315 Mon Sep 17 00:00:00 2001 +From: Kjetil Oftedal <oftedal@gmail.com> +Date: Mon, 29 Aug 2011 00:16:28 +0200 +Subject: sparc32,sun4d: Change IPI IRQ level to prevent collision + between IPI and timer interrupt + +From: Kjetil Oftedal <oftedal@gmail.com> + +commit 38f7f8f05e8239e9871f7e1c4b0a842080e85315 upstream. + +On Sun4d systems running in SMP mode, IRQ 14 is used for timer interrupts +and has a specialized interrupt handler. IPI is currently set to use IRQ 14 +as well, which causes it to trigger the timer interrupt handler, and not the +IPI interrupt handler. + +The IPI interrupt is therefore changed to IRQ 13, which is the highest +normally handled interrupt. This IRQ is also used for SBUS interrupts, +however there is nothing in the IPI/SBUS interrupt handlers that indicate +that they will not handle sharing the interrupt. +(IRQ 13 is indicated as audio interrupt, which is unlikely to be found in a +sun4d system) + +Signed-off-by: Kjetil Oftedal <oftedal@gmail.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + arch/sparc/kernel/irq.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/sparc/kernel/irq.h ++++ b/arch/sparc/kernel/irq.h +@@ -88,7 +88,7 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int) + #define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu) + + /* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */ +-#define SUN4D_IPI_IRQ 14 ++#define SUN4D_IPI_IRQ 13 + + extern void sun4d_ipi_interrupt(void); + diff --git a/queue-3.0/sparc32-unbreak-arch_write_unlock.patch b/queue-3.0/sparc32-unbreak-arch_write_unlock.patch new file mode 100644 index 0000000000..7eec1f6579 --- /dev/null +++ b/queue-3.0/sparc32-unbreak-arch_write_unlock.patch @@ -0,0 +1,60 @@ +From 3f6aa0b113846a8628baa649af422cfc6fb1d786 Mon Sep 17 00:00:00 2001 +From: Mikael Pettersson <mikpe@it.uu.se> +Date: Mon, 15 Aug 2011 10:11:50 +0000 +Subject: sparc32: unbreak arch_write_unlock() + +From: Mikael Pettersson <mikpe@it.uu.se> + +commit 3f6aa0b113846a8628baa649af422cfc6fb1d786 upstream. + +The sparc32 version of arch_write_unlock() is just a plain assignment. +Unfortunately this allows the compiler to schedule side-effects in a +protected region to occur after the HW-level unlock, which is broken. +E.g., the following trivial test case gets miscompiled: + + #include <linux/spinlock.h> + rwlock_t lock; + int counter; + void foo(void) { write_lock(&lock); ++counter; write_unlock(&lock); } + +Fixed by adding a compiler memory barrier to arch_write_unlock(). The +sparc64 version combines the barrier and assignment into a single asm(), +and implements the operation as a static inline, so that's what I did too. + +Compile-tested with sparc32_defconfig + CONFIG_SMP=y. + +Signed-off-by: Mikael Pettersson <mikpe@it.uu.se> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + arch/sparc/include/asm/spinlock_32.h | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/arch/sparc/include/asm/spinlock_32.h ++++ b/arch/sparc/include/asm/spinlock_32.h +@@ -131,6 +131,15 @@ static inline void arch_write_lock(arch_ + *(volatile __u32 *)&lp->lock = ~0U; + } + ++static void inline arch_write_unlock(arch_rwlock_t *lock) ++{ ++ __asm__ __volatile__( ++" st %%g0, [%0]" ++ : /* no outputs */ ++ : "r" (lock) ++ : "memory"); ++} ++ + static inline int arch_write_trylock(arch_rwlock_t *rw) + { + unsigned int val; +@@ -175,8 +184,6 @@ static inline int __arch_read_trylock(ar + res; \ + }) + +-#define arch_write_unlock(rw) do { (rw)->lock = 0; } while(0) +- + #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) + #define arch_read_lock_flags(rw, flags) arch_read_lock(rw) + #define arch_write_lock_flags(rw, flags) arch_write_lock(rw) diff --git a/queue-3.0/sparc64-remove-unnecessary-macros-from-spinlock_64.h.patch b/queue-3.0/sparc64-remove-unnecessary-macros-from-spinlock_64.h.patch new file mode 100644 index 0000000000..ed3d3bf6bf --- /dev/null +++ b/queue-3.0/sparc64-remove-unnecessary-macros-from-spinlock_64.h.patch @@ -0,0 +1,45 @@ +From a0fba3eb059e73fed2d376a901f8117734c12f1f Mon Sep 17 00:00:00 2001 +From: Mikael Pettersson <mikpe@it.uu.se> +Date: Mon, 15 Aug 2011 10:10:31 +0000 +Subject: sparc64: remove unnecessary macros from spinlock_64.h + +From: Mikael Pettersson <mikpe@it.uu.se> + +commit a0fba3eb059e73fed2d376a901f8117734c12f1f upstream. + +The sparc64 spinlock_64.h contains a number of operations defined +first as static inline functions, and then as macros with the same +names and parameters as the functions. Maybe this was needed at +some point in the past, but now nothing seems to depend on these +macros (checked with a recursive grep looking for ifdefs on these +names). Other archs don't define these identity-macros. + +So this patch deletes these unnecessary macros. + +Compile-tested with sparc64_defconfig. + +Signed-off-by: Mikael Pettersson <mikpe@it.uu.se> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + arch/sparc/include/asm/spinlock_64.h | 6 ------ + 1 file changed, 6 deletions(-) + +--- a/arch/sparc/include/asm/spinlock_64.h ++++ b/arch/sparc/include/asm/spinlock_64.h +@@ -210,14 +210,8 @@ static int inline arch_write_trylock(arc + return result; + } + +-#define arch_read_lock(p) arch_read_lock(p) + #define arch_read_lock_flags(p, f) arch_read_lock(p) +-#define arch_read_trylock(p) arch_read_trylock(p) +-#define arch_read_unlock(p) arch_read_unlock(p) +-#define arch_write_lock(p) arch_write_lock(p) + #define arch_write_lock_flags(p, f) arch_write_lock(p) +-#define arch_write_unlock(p) arch_write_unlock(p) +-#define arch_write_trylock(p) arch_write_trylock(p) + + #define arch_read_can_lock(rw) (!((rw)->lock & 0x80000000UL)) + #define arch_write_can_lock(rw) (!(rw)->lock) diff --git a/queue-3.0/sparc64-set-have_c_recordmcount.patch b/queue-3.0/sparc64-set-have_c_recordmcount.patch new file mode 100644 index 0000000000..c4946e1c76 --- /dev/null +++ b/queue-3.0/sparc64-set-have_c_recordmcount.patch @@ -0,0 +1,25 @@ +From e5fa8bd53dbe1c3ebf4da2297b1fde3ed3a5e428 Mon Sep 17 00:00:00 2001 +From: "David S. Miller" <davem@davemloft.net> +Date: Mon, 15 Aug 2011 14:45:17 -0700 +Subject: sparc64: Set HAVE_C_RECORDMCOUNT + +From: "David S. Miller" <davem@davemloft.net> + +[ Upstream commit 178a29600340bef5b13cd4157053679debe35351 ] + +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + arch/sparc/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/sparc/Kconfig ++++ b/arch/sparc/Kconfig +@@ -53,6 +53,7 @@ config SPARC64 + select HAVE_PERF_EVENTS + select PERF_USE_VMALLOC + select IRQ_PREFLOW_FASTEOI ++ select HAVE_C_RECORDMCOUNT + + config ARCH_DEFCONFIG + string |