diff options
author | Chris Metcalf <cmetcalf@tilera.com> | 2012-03-29 14:52:00 -0400 |
---|---|---|
committer | Chris Metcalf <cmetcalf@tilera.com> | 2012-04-02 12:12:48 -0400 |
commit | e17235382dbb05f70146e141e4b780fd069050dc (patch) | |
tree | d4da45df23c48ac7e0e4f61821125174a39e436a | |
parent | 5f639fdcd8c186c8128c616e94a7e7b159c968ae (diff) |
arch/tile: work around a hardware issue with the return-address stack
In certain circumstances we need to do a bunch of jump-and-link
instructions to fill the hardware return-address stack with nonzero values.
Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
-rw-r--r-- | arch/tile/include/asm/traps.h | 6 | ||||
-rw-r--r-- | arch/tile/kernel/intvec_64.S | 12 | ||||
-rw-r--r-- | arch/tile/kernel/traps.c | 6 |
3 files changed, 22 insertions, 2 deletions
diff --git a/arch/tile/include/asm/traps.h b/arch/tile/include/asm/traps.h index 5f20f920f932..e28c3df4176a 100644 --- a/arch/tile/include/asm/traps.h +++ b/arch/tile/include/asm/traps.h | |||
@@ -64,7 +64,11 @@ void do_breakpoint(struct pt_regs *, int fault_num); | |||
64 | 64 | ||
65 | 65 | ||
66 | #ifdef __tilegx__ | 66 | #ifdef __tilegx__ |
67 | /* kernel/single_step.c */ | ||
67 | void gx_singlestep_handle(struct pt_regs *, int fault_num); | 68 | void gx_singlestep_handle(struct pt_regs *, int fault_num); |
69 | |||
70 | /* kernel/intvec_64.S */ | ||
71 | void fill_ra_stack(void); | ||
68 | #endif | 72 | #endif |
69 | 73 | ||
70 | #endif /* _ASM_TILE_SYSCALLS_H */ | 74 | #endif /* _ASM_TILE_TRAPS_H */ |
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S index 79c93e10ba27..2c181c864ef7 100644 --- a/arch/tile/kernel/intvec_64.S +++ b/arch/tile/kernel/intvec_64.S | |||
@@ -1156,6 +1156,18 @@ int_unalign: | |||
1156 | push_extra_callee_saves r0 | 1156 | push_extra_callee_saves r0 |
1157 | j do_trap | 1157 | j do_trap |
1158 | 1158 | ||
1159 | /* Fill the return address stack with nonzero entries. */ | ||
1160 | STD_ENTRY(fill_ra_stack) | ||
1161 | { | ||
1162 | move r0, lr | ||
1163 | jal 1f | ||
1164 | } | ||
1165 | 1: jal 2f | ||
1166 | 2: jal 3f | ||
1167 | 3: jal 4f | ||
1168 | 4: jrp r0 | ||
1169 | STD_ENDPROC(fill_ra_stack) | ||
1170 | |||
1159 | /* Include .intrpt1 array of interrupt vectors */ | 1171 | /* Include .intrpt1 array of interrupt vectors */ |
1160 | .section ".intrpt1", "ax" | 1172 | .section ".intrpt1", "ax" |
1161 | 1173 | ||
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c index 2bb6602a1ee7..32acfd9e23d0 100644 --- a/arch/tile/kernel/traps.c +++ b/arch/tile/kernel/traps.c | |||
@@ -289,7 +289,10 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
289 | address = regs->pc; | 289 | address = regs->pc; |
290 | break; | 290 | break; |
291 | #ifdef __tilegx__ | 291 | #ifdef __tilegx__ |
292 | case INT_ILL_TRANS: | 292 | case INT_ILL_TRANS: { |
293 | /* Avoid a hardware erratum with the return address stack. */ | ||
294 | fill_ra_stack(); | ||
295 | |||
293 | signo = SIGSEGV; | 296 | signo = SIGSEGV; |
294 | code = SEGV_MAPERR; | 297 | code = SEGV_MAPERR; |
295 | if (reason & SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK) | 298 | if (reason & SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK) |
@@ -297,6 +300,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
297 | else | 300 | else |
298 | address = 0; /* FIXME: GX: single-step for address */ | 301 | address = 0; /* FIXME: GX: single-step for address */ |
299 | break; | 302 | break; |
303 | } | ||
300 | #endif | 304 | #endif |
301 | default: | 305 | default: |
302 | panic("Unexpected do_trap interrupt number %d", fault_num); | 306 | panic("Unexpected do_trap interrupt number %d", fault_num); |