]> pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
[SPARC64]: Fix %tstate ASI handling in start_thread{,32}()
authorDavid S. Miller <davem@sunset.davemloft.net>
Thu, 23 Feb 2006 00:20:11 +0000 (16:20 -0800)
committerDavid S. Miller <davem@sunset.davemloft.net>
Mon, 20 Mar 2006 09:13:57 +0000 (01:13 -0800)
Niagara helps us find a ancient bug in the sparc64 port :-)

The ASI_* values are plain constant defines, thus signed 32-bit
on sparc64.  To put shift this into the regs->tstate value we were
doing or'ing "(ASI_PNF << 24)" into there.

ASI_PNF is 0x82 and shifted left by 24 makes that topmost bit the
sign bit in a 32-bit value.  This would get sign extended to 64-bits
and thus corrupt the top-half of the reg->tstate value.

This never caused problems in pre-Niagara cpus because the only thing
up there were the condition code values.  But Niagara has the global
register level field, and this all 1's value is illegal there so
Niagara gives an illegal instruction trap due to this bug.

I'm pretty sure this bug is about as old as the sparc64 port itself.

This also points out that we weren't setting ASI_PNF for 32-bit tasks.
We should, so fix that while we're here.

Signed-off-by: David S. Miller <davem@davemloft.net>
include/asm-sparc64/processor.h

index b3889f3f943a2bda36514154c6ba76565dce6ba9..685479fb436472317a58b2e314a75594ba6378f3 100644 (file)
@@ -91,7 +91,8 @@ extern unsigned long thread_saved_pc(struct task_struct *);
 /* Do necessary setup to start up a newly executed thread. */
 #define start_thread(regs, pc, sp) \
 do { \
 /* Do necessary setup to start up a newly executed thread. */
 #define start_thread(regs, pc, sp) \
 do { \
-       regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_INITIAL_MM|TSTATE_IE) | (ASI_PNF << 24); \
+       unsigned long __asi = ASI_PNF; \
+       regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_INITIAL_MM|TSTATE_IE) | (__asi << 24UL); \
        regs->tpc = ((pc & (~3)) - 4); \
        regs->tnpc = regs->tpc + 4; \
        regs->y = 0; \
        regs->tpc = ((pc & (~3)) - 4); \
        regs->tnpc = regs->tpc + 4; \
        regs->y = 0; \
@@ -128,10 +129,10 @@ do { \
 
 #define start_thread32(regs, pc, sp) \
 do { \
 
 #define start_thread32(regs, pc, sp) \
 do { \
+       unsigned long __asi = ASI_PNF; \
        pc &= 0x00000000ffffffffUL; \
        sp &= 0x00000000ffffffffUL; \
        pc &= 0x00000000ffffffffUL; \
        sp &= 0x00000000ffffffffUL; \
-\
-       regs->tstate = (regs->tstate & (TSTATE_CWP))|(TSTATE_INITIAL_MM|TSTATE_IE|TSTATE_AM); \
+       regs->tstate = (regs->tstate & (TSTATE_CWP))|(TSTATE_INITIAL_MM|TSTATE_IE|TSTATE_AM) | (__asi << 24UL); \
        regs->tpc = ((pc & (~3)) - 4); \
        regs->tnpc = regs->tpc + 4; \
        regs->y = 0; \
        regs->tpc = ((pc & (~3)) - 4); \
        regs->tnpc = regs->tpc + 4; \
        regs->y = 0; \