1 From 17290231df16eeee5dfc198dbf5ee4b419996dcd Mon Sep 17 00:00:00 2001
2 From: Max Filippov <jcmvbkbc@gmail.com>
3 Date: Sat, 24 May 2014 21:48:28 +0400
4 Subject: xtensa: add fixup for double exception raised in window overflow
6 From: Max Filippov <jcmvbkbc@gmail.com>
8 commit 17290231df16eeee5dfc198dbf5ee4b419996dcd upstream.
10 There are two FIXMEs in the double exception handler 'for the extremely
11 unlikely case'. This case gets hit by gcc during kernel build once in
12 a few hours, resulting in an unrecoverable exception condition.
14 Provide missing fixup routine to handle this case. Double exception
15 literals now need 8 more bytes, add them to the linker script.
17 Also replace bbsi instructions with bbsi.l as we're branching depending
18 on 8th and 7th LSB-based bits of exception address.
20 This may be tested by adding the explicit DTLB invalidation to window
21 overflow handlers, like the following:
23 # --- a/arch/xtensa/kernel/vectors.S
24 # +++ b/arch/xtensa/kernel/vectors.S
25 # @@ -592,6 +592,14 @@ ENDPROC(_WindowUnderflow4)
26 # ENTRY_ALIGN64(_WindowOverflow8)
41 Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
42 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
45 arch/xtensa/kernel/vectors.S | 158 +++++++++++++++++++++++++++++++++------
46 arch/xtensa/kernel/vmlinux.lds.S | 4
47 2 files changed, 138 insertions(+), 24 deletions(-)
49 --- a/arch/xtensa/kernel/vectors.S
50 +++ b/arch/xtensa/kernel/vectors.S
51 @@ -376,38 +376,42 @@ _DoubleExceptionVector_WindowOverflow:
52 beqz a2, 1f # if at start of vector, don't restore
55 - bbsi a0, 8, 1f # don't restore except for overflow 8 and 12
57 + bbsi.l a0, 8, 1f # don't restore except for overflow 8 and 12
60 + * This fixup handler is for the extremely unlikely case where the
61 + * overflow handler's reference thru a0 gets a hardware TLB refill
62 + * that bumps out the (distinct, aliasing) TLB entry that mapped its
63 + * prior references thru a9/a13, and where our reference now thru
64 + * a9/a13 gets a 2nd-level miss exception (not hardware TLB refill).
66 + movi a2, window_overflow_restore_a0_fixup
67 + s32i a2, a3, EXC_TABLE_FIXUP
68 + l32i a2, a3, EXC_TABLE_DOUBLE_SAVE
74 * Restore a0 as saved by _WindowOverflow8().
76 - * FIXME: we really need a fixup handler for this L32E,
77 - * for the extremely unlikely case where the overflow handler's
78 - * reference thru a0 gets a hardware TLB refill that bumps out
79 - * the (distinct, aliasing) TLB entry that mapped its prior
80 - * references thru a9, and where our reference now thru a9
81 - * gets a 2nd-level miss exception (not hardware TLB refill).
85 - wsr a2, depc # replace the saved a0
88 + wsr a0, depc # replace the saved a0
93 * Restore a0 as saved by _WindowOverflow12().
95 - * FIXME: we really need a fixup handler for this L32E,
96 - * for the extremely unlikely case where the overflow handler's
97 - * reference thru a0 gets a hardware TLB refill that bumps out
98 - * the (distinct, aliasing) TLB entry that mapped its prior
99 - * references thru a13, and where our reference now thru a13
100 - * gets a 2nd-level miss exception (not hardware TLB refill).
104 - wsr a2, depc # replace the saved a0
106 + wsr a0, depc # replace the saved a0
110 + s32i a0, a3, EXC_TABLE_FIXUP
111 + s32i a2, a3, EXC_TABLE_DOUBLE_SAVE
114 * Restore WindowBase while leaving all address registers restored.
115 @@ -449,6 +453,7 @@ _DoubleExceptionVector_WindowOverflow:
119 +_DoubleExceptionVector_handle_exception:
121 l32i a0, a0, EXC_TABLE_FAST_USER
123 @@ -464,11 +469,120 @@ _DoubleExceptionVector_WindowOverflow:
127 - .end literal_prefix
129 ENDPROC(_DoubleExceptionVector)
132 + * Fixup handler for TLB miss in double exception handler for window owerflow.
133 + * We get here with windowbase set to the window that was being spilled and
134 + * a0 trashed. a0 bit 7 determines if this is a call8 (bit clear) or call12
135 + * (bit set) window.
137 + * We do the following here:
138 + * - go to the original window retaining a0 value;
139 + * - set up exception stack to return back to appropriate a0 restore code
140 + * (we'll need to rotate window back and there's no place to save this
141 + * information, use different return address for that);
142 + * - handle the exception;
143 + * - go to the window that was being spilled;
144 + * - set up window_overflow_restore_a0_fixup as a fixup routine;
146 + * - restore the original window;
147 + * - reset the default fixup routine;
148 + * - return to user. By the time we get to this fixup handler all information
149 + * about the conditions of the original double exception that happened in
150 + * the window overflow handler is lost, so we just return to userspace to
151 + * retry overflow from start.
153 + * a0: value of depc, original value in depc
154 + * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
155 + * a3: exctable, original value in excsave1
158 +ENTRY(window_overflow_restore_a0_fixup)
161 + extui a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
165 + l32i a2, a3, EXC_TABLE_DOUBLE_SAVE
168 + _beqi a0, 1, .Lhandle_1
169 + _beqi a0, 3, .Lhandle_3
171 + .macro overflow_fixup_handle_exception_pane n
178 + l32i a2, a3, EXC_TABLE_KSTK
179 + s32i a0, a2, PT_AREG0
181 + movi a0, .Lrestore_\n
182 + s32i a0, a2, PT_DEPC
184 + j _DoubleExceptionVector_handle_exception
188 + overflow_fixup_handle_exception_pane 2
190 + overflow_fixup_handle_exception_pane 1
192 + overflow_fixup_handle_exception_pane 3
194 + .macro overflow_fixup_restore_a0_pane n
197 + /* Need to preserve a0 value here to be able to handle exception
198 + * that may occur on a0 reload from stack. It may occur because
199 + * TLB miss handler may not be atomic and pointer to page table
200 + * may be lost before we get here. There are no free registers,
201 + * so we need to use EXC_TABLE_DOUBLE_SAVE area.
204 + s32i a2, a3, EXC_TABLE_DOUBLE_SAVE
205 + movi a2, window_overflow_restore_a0_fixup
206 + s32i a2, a3, EXC_TABLE_FIXUP
207 + l32i a2, a3, EXC_TABLE_DOUBLE_SAVE
220 + overflow_fixup_restore_a0_pane 2
222 +.Lset_default_fixup:
224 + s32i a2, a3, EXC_TABLE_DOUBLE_SAVE
226 + s32i a2, a3, EXC_TABLE_FIXUP
227 + l32i a2, a3, EXC_TABLE_DOUBLE_SAVE
232 + overflow_fixup_restore_a0_pane 1
233 + j .Lset_default_fixup
235 + overflow_fixup_restore_a0_pane 3
236 + j .Lset_default_fixup
238 +ENDPROC(window_overflow_restore_a0_fixup)
240 + .end literal_prefix
242 * Debug interrupt vector
244 * There is not much space here, so simply jump to another handler.
245 --- a/arch/xtensa/kernel/vmlinux.lds.S
246 +++ b/arch/xtensa/kernel/vmlinux.lds.S
247 @@ -269,13 +269,13 @@ SECTIONS
248 .UserExceptionVector.literal)
249 SECTION_VECTOR (_DoubleExceptionVector_literal,
250 .DoubleExceptionVector.literal,
251 - DOUBLEEXC_VECTOR_VADDR - 16,
252 + DOUBLEEXC_VECTOR_VADDR - 40,
253 SIZEOF(.UserExceptionVector.text),
254 .UserExceptionVector.text)
255 SECTION_VECTOR (_DoubleExceptionVector_text,
256 .DoubleExceptionVector.text,
257 DOUBLEEXC_VECTOR_VADDR,
260 .DoubleExceptionVector.literal)
262 . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3;