aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-02-22 19:20:11 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-03-20 04:13:57 -0500
commit0f05da6d577b80eb00f15994c86e4812ae60f1b9 (patch)
tree39d981c896ab6b90aa30f124fb25cbdf4f242c83
parentfc504928677049f0ad3f1fd4e0bb3908172df8f3 (diff)
[SPARC64]: Fix %tstate ASI handling in start_thread{,32}()
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>
-rw-r--r--include/asm-sparc64/processor.h7
1 files changed, 4 insertions, 3 deletions
diff --git a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h
index b3889f3f943a..685479fb4364 100644
--- a/include/asm-sparc64/processor.h
+++ b/include/asm-sparc64/processor.h
@@ -91,7 +91,8 @@ extern unsigned long thread_saved_pc(struct task_struct *);
91/* Do necessary setup to start up a newly executed thread. */ 91/* Do necessary setup to start up a newly executed thread. */
92#define start_thread(regs, pc, sp) \ 92#define start_thread(regs, pc, sp) \
93do { \ 93do { \
94 regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_INITIAL_MM|TSTATE_IE) | (ASI_PNF << 24); \ 94 unsigned long __asi = ASI_PNF; \
95 regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_INITIAL_MM|TSTATE_IE) | (__asi << 24UL); \
95 regs->tpc = ((pc & (~3)) - 4); \ 96 regs->tpc = ((pc & (~3)) - 4); \
96 regs->tnpc = regs->tpc + 4; \ 97 regs->tnpc = regs->tpc + 4; \
97 regs->y = 0; \ 98 regs->y = 0; \
@@ -128,10 +129,10 @@ do { \
128 129
129#define start_thread32(regs, pc, sp) \ 130#define start_thread32(regs, pc, sp) \
130do { \ 131do { \
132 unsigned long __asi = ASI_PNF; \
131 pc &= 0x00000000ffffffffUL; \ 133 pc &= 0x00000000ffffffffUL; \
132 sp &= 0x00000000ffffffffUL; \ 134 sp &= 0x00000000ffffffffUL; \
133\ 135 regs->tstate = (regs->tstate & (TSTATE_CWP))|(TSTATE_INITIAL_MM|TSTATE_IE|TSTATE_AM) | (__asi << 24UL); \
134 regs->tstate = (regs->tstate & (TSTATE_CWP))|(TSTATE_INITIAL_MM|TSTATE_IE|TSTATE_AM); \
135 regs->tpc = ((pc & (~3)) - 4); \ 136 regs->tpc = ((pc & (~3)) - 4); \
136 regs->tnpc = regs->tpc + 4; \ 137 regs->tnpc = regs->tpc + 4; \
137 regs->y = 0; \ 138 regs->y = 0; \