diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2011-08-30 15:03:07 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-08-30 15:03:07 -0700 |
commit | 2edff1c16ec4396f87e40e8161fb91e6fcc92150 (patch) | |
tree | 0074e678c2bf993231913396cb69dc66cc987d3c | |
parent | 7b25235cec5b8b019850d9a57192c7b5e0c0467f (diff) | |
download | longterm-queue-2.6.32-2edff1c16ec4396f87e40e8161fb91e6fcc92150.tar.gz |
.32 patches
6 files changed, 1374 insertions, 0 deletions
diff --git a/queue-2.6.32/fix-broken-backport-for-ipv6-tunnels.patch b/queue-2.6.32/fix-broken-backport-for-ipv6-tunnels.patch new file mode 100644 index 0000000..9ce3adb --- /dev/null +++ b/queue-2.6.32/fix-broken-backport-for-ipv6-tunnels.patch @@ -0,0 +1,49 @@ +From psomas@gentoo.org Tue Aug 30 14:52:07 2011 +From: Stratos Psomadakis <psomas@gentoo.org> +Date: Tue, 30 Aug 2011 17:48:08 +0300 +Subject: Fix broken backport for IPv6 tunnels +To: stable@kernel.org +Cc: Stratos Psomadakis <psomas@gentoo.org> +Message-ID: <1314715688-26919-1-git-send-email-psomas@gentoo.org> + +From: Stratos Psomadakis <psomas@gentoo.org> + +Fix broken backport for IPv6 tunnels in 2.6.32-longterm kernels. + +upstream commit d5aa407f59f5b83d2c50ec88f5bf56d40f1f8978 ("tunnels: fix +netns vs proto registration ordering") , which was included in +2.6.32.44-longterm, was not backported correctly, and results in a NULL +pointer dereference in ip6_tunnel.c for longterm kernels >=2.6.32.44 + +Use [un]register_pernet_gen_device() instead of +[un]register_pernet_device() to fix it. + +Signed-off-by: Stratos Psomadakis <psomas@gentoo.org> +Cc: Wolfgang Walter <wolfgang.walter@stwm.de> +Cc: Tim Gardner <tim.gardner@canonical.com> +Cc: Andy Whitcroft <apw@canonical.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + net/ipv6/ip6_tunnel.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -1466,7 +1466,7 @@ static int __init ip6_tunnel_init(void) + { + int err; + +- err = register_pernet_device(&ip6_tnl_net_ops); ++ err = register_pernet_gen_device(&ip6_tnl_net_id, &ip6_tnl_net_ops); + if (err < 0) + goto out_pernet; + +@@ -1487,7 +1487,7 @@ static int __init ip6_tunnel_init(void) + out_ip6ip6: + xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); + out_ip4ip6: +- unregister_pernet_device(&ip6_tnl_net_ops); ++ unregister_pernet_gen_device(ip6_tnl_net_id, &ip6_tnl_net_ops); + out_pernet: + return err; + } diff --git a/queue-2.6.32/ipv6-add-gso-support-on-forwarding-path.patch b/queue-2.6.32/ipv6-add-gso-support-on-forwarding-path.patch new file mode 100644 index 0000000..18f9e22 --- /dev/null +++ b/queue-2.6.32/ipv6-add-gso-support-on-forwarding-path.patch @@ -0,0 +1,42 @@ +From 0aa68271510ae2b221d4b60892103837be63afe4 Mon Sep 17 00:00:00 2001 +From: Herbert Xu <herbert@gondor.apana.org.au> +Date: Thu, 27 May 2010 16:14:30 -0700 +Subject: ipv6: Add GSO support on forwarding path + +From: Herbert Xu <herbert@gondor.apana.org.au> + +commit 0aa68271510ae2b221d4b60892103837be63afe4 upstream. + +Currently we disallow GSO packets on the IPv6 forward path. +This patch fixes this. + +Note that I discovered that our existing GSO MTU checks (e.g., +IPv4 forwarding) are buggy in that they skip the check altogether, +when they really should be checking gso_size + header instead. + +I have also been lazy here in that I haven't bothered to segment +the GSO packet by hand before generating an ICMP message. Someone +should add that to be 100% correct. + +Reported-by: Ralf Baechle <ralf@linux-mips.org> +Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Apollon Oikonomopoulos <apoikos@gmail.com> +Signed-off-by: Faidon Liambotis <paravoid@debian.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + net/ipv6/ip6_output.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -510,7 +510,7 @@ int ip6_forward(struct sk_buff *skb) + } + } + +- if (skb->len > dst_mtu(dst)) { ++ if (skb->len > dst_mtu(dst) && !skb_is_gso(skb)) { + /* Again, force OUTPUT device used as source address */ + skb->dev = dst->dev; + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev); diff --git a/queue-2.6.32/net-fix-ipv6-gso-type-checks-in-intel-ethernet-drivers.patch b/queue-2.6.32/net-fix-ipv6-gso-type-checks-in-intel-ethernet-drivers.patch new file mode 100644 index 0000000..daf5bf3 --- /dev/null +++ b/queue-2.6.32/net-fix-ipv6-gso-type-checks-in-intel-ethernet-drivers.patch @@ -0,0 +1,73 @@ +From 8e1e8a4779cb23c1d9f51e9223795e07ec54d77a Mon Sep 17 00:00:00 2001 +From: Sridhar Samudrala <sri@us.ibm.com> +Date: Sat, 23 Jan 2010 02:02:21 -0800 +Subject: net: Fix IPv6 GSO type checks in Intel ethernet drivers + +From: Sridhar Samudrala <sri@us.ibm.com> + +commit 8e1e8a4779cb23c1d9f51e9223795e07ec54d77a upstream. + +Found this problem when testing IPv6 from a KVM guest to a remote +host via e1000e device on the host. +The following patch fixes the check for IPv6 GSO packet in Intel +ethernet drivers to use skb_is_gso_v6(). SKB_GSO_DODGY is also set +when packets are forwarded from a guest. + +Signed-off-by: Sridhar Samudrala <sri@us.ibm.com> +Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Faidon Liambotis <paravoid@debian.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/net/e1000e/netdev.c | 2 +- + drivers/net/igb/igb_main.c | 2 +- + drivers/net/igbvf/netdev.c | 2 +- + drivers/net/ixgbe/ixgbe_main.c | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/e1000e/netdev.c ++++ b/drivers/net/e1000e/netdev.c +@@ -3807,7 +3807,7 @@ static int e1000_tso(struct e1000_adapte + 0); + cmd_length = E1000_TXD_CMD_IP; + ipcse = skb_transport_offset(skb) - 1; +- } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { ++ } else if (skb_is_gso_v6(skb)) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, +--- a/drivers/net/igb/igb_main.c ++++ b/drivers/net/igb/igb_main.c +@@ -3032,7 +3032,7 @@ static inline int igb_tso_adv(struct igb + iph->daddr, 0, + IPPROTO_TCP, + 0); +- } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { ++ } else if (skb_is_gso_v6(skb)) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, +--- a/drivers/net/igbvf/netdev.c ++++ b/drivers/net/igbvf/netdev.c +@@ -1953,7 +1953,7 @@ static int igbvf_tso(struct igbvf_adapte + iph->daddr, 0, + IPPROTO_TCP, + 0); +- } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { ++ } else if (skb_is_gso_v6(skb)) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, +--- a/drivers/net/ixgbe/ixgbe_main.c ++++ b/drivers/net/ixgbe/ixgbe_main.c +@@ -4881,7 +4881,7 @@ static int ixgbe_tso(struct ixgbe_adapte + IPPROTO_TCP, + 0); + adapter->hw_tso_ctxt++; +- } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { ++ } else if (skb_is_gso_v6(skb)) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, diff --git a/queue-2.6.32/series b/queue-2.6.32/series index e8ffeb2..045e85e 100644 --- a/queue-2.6.32/series +++ b/queue-2.6.32/series @@ -2,3 +2,8 @@ usb-ftdi_sio-add-calao-reference-board-support.patch usb-ehci-do-not-rely-on-port_suspend-to-stop-usb-resuming-in-ehci_bus_resume.patch rt2x00-do-not-drop-usb-dev-reference-counter-on-suspend.patch atm-br2684-fix-oops-due-to-skb-dev-being-null.patch +sparc-allow-handling-signals-when-stack-is-corrupted.patch +sparc-fix-array-bounds-error-setting-up-pcic-nmi-trap.patch +fix-broken-backport-for-ipv6-tunnels.patch +net-fix-ipv6-gso-type-checks-in-intel-ethernet-drivers.patch +ipv6-add-gso-support-on-forwarding-path.patch diff --git a/queue-2.6.32/sparc-allow-handling-signals-when-stack-is-corrupted.patch b/queue-2.6.32/sparc-allow-handling-signals-when-stack-is-corrupted.patch new file mode 100644 index 0000000..5bdc380 --- /dev/null +++ b/queue-2.6.32/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 +@@ -24,6 +24,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-2.6.32/sparc-fix-array-bounds-error-setting-up-pcic-nmi-trap.patch b/queue-2.6.32/sparc-fix-array-bounds-error-setting-up-pcic-nmi-trap.patch new file mode 100644 index 0000000..3bf846d --- /dev/null +++ b/queue-2.6.32/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 +@@ -350,8 +350,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]; |