summaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2012-03-29 14:52:00 -0400
committerChris Metcalf <cmetcalf@tilera.com>2012-04-02 12:12:48 -0400
commite17235382dbb05f70146e141e4b780fd069050dc (patch)
treed4da45df23c48ac7e0e4f61821125174a39e436a /arch/tile/kernel
parent5f639fdcd8c186c8128c616e94a7e7b159c968ae (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>
Diffstat (limited to 'arch/tile/kernel')
-rw-r--r--arch/tile/kernel/intvec_64.S12
-rw-r--r--arch/tile/kernel/traps.c6
2 files changed, 17 insertions, 1 deletions
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
index 79c93e10ba2..2c181c864ef 100644
--- a/arch/tile/kernel/intvec_64.S
+++ b/arch/tile/kernel/intvec_64.S
@@ -1156,6 +1156,18 @@ int_unalign:
push_extra_callee_saves r0
j do_trap
+/* Fill the return address stack with nonzero entries. */
+STD_ENTRY(fill_ra_stack)
+ {
+ move r0, lr
+ jal 1f
+ }
+1: jal 2f
+2: jal 3f
+3: jal 4f
+4: jrp r0
+ STD_ENDPROC(fill_ra_stack)
+
/* Include .intrpt1 array of interrupt vectors */
.section ".intrpt1", "ax"
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index 2bb6602a1ee..32acfd9e23d 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,
address = regs->pc;
break;
#ifdef __tilegx__
- case INT_ILL_TRANS:
+ case INT_ILL_TRANS: {
+ /* Avoid a hardware erratum with the return address stack. */
+ fill_ra_stack();
+
signo = SIGSEGV;
code = SEGV_MAPERR;
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,
else
address = 0; /* FIXME: GX: single-step for address */
break;
+ }
#endif
default:
panic("Unexpected do_trap interrupt number %d", fault_num);