[PATCH] m68knommu: fix a5 reg corruption in signal handlers

This is a patch adapted from a posting by Andrea Tarani which was
pointed out to me by Bernardo Innocenti. Thanks to both of them for
their help and patience.

The original posting is here:
http://mailman.uclinux.org/pipermail/uclinux-dev/2005-July/033543.html

The problem first manifest itself as busybox ping terminating with an
"Illegal instruction". I reduced this to a test case and found that
variable size arrays allocated on the stack could lead to stacks not
aligned on 32 bit boundaries. For the Coldfire this proved fatal.

Having been pointed out this patch by Bernardo, I applied it and it
fixed the first test case. I then went back to busybox's ping. This
still failed with "Illegal instruction", but in a different way. Before
it depended on the size allocated for the ping buffer, now it happened
every time. I also found it depended on optimisation level (gcc-3.4.0)
-Os was okay but not -O2.

After a lot of looking, it turned out that register a5 was being
corrupted by the signal handler (after applying the patch). I re-worked
the patch a bit to save/restore a5 and now all seems well.

Patch submitted by Stuart Hughs <stuarth@freescale.com>

Signed-off-by: Greg Ungerer <gerg@uclinux.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Greg Ungerer and committed by
Linus Torvalds
01829e72 afc7cd89

+8
+8
arch/m68knommu/kernel/signal.c
··· 285 285 regs->d1 = context.sc_d1; 286 286 regs->a0 = context.sc_a0; 287 287 regs->a1 = context.sc_a1; 288 + ((struct switch_stack *)regs - 1)->a5 = context.sc_a5; 288 289 regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); 289 290 regs->pc = context.sc_pc; 290 291 regs->orig_d0 = -1; /* disable syscall checks */ ··· 499 498 sc->sc_d1 = regs->d1; 500 499 sc->sc_a0 = regs->a0; 501 500 sc->sc_a1 = regs->a1; 501 + sc->sc_a5 = ((struct switch_stack *)regs - 1)->a5; 502 502 sc->sc_sr = regs->sr; 503 503 sc->sc_pc = regs->pc; 504 504 sc->sc_formatvec = regs->format << 12 | regs->vector; ··· 599 597 /* Set up registers for signal handler */ 600 598 wrusp ((unsigned long) frame); 601 599 regs->pc = (unsigned long) ka->sa.sa_handler; 600 + ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data; 601 + regs->format = 0x4; /*set format byte to make stack appear modulo 4 602 + which it will be when doing the rte */ 602 603 603 604 adjust_stack: 604 605 /* Prepare to skip over the extra stuff in the exception frame. */ ··· 669 664 /* Set up registers for signal handler */ 670 665 wrusp ((unsigned long) frame); 671 666 regs->pc = (unsigned long) ka->sa.sa_handler; 667 + ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data; 668 + regs->format = 0x4; /*set format byte to make stack appear modulo 4 669 + which it will be when doing the rte */ 672 670 673 671 adjust_stack: 674 672 /* Prepare to skip over the extra stuff in the exception frame. */