aboutsummaryrefslogtreecommitdiffstats
path: root/arch/xtensa
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2013-07-03 12:23:28 -0400
committerChris Zankel <chris@zankel.net>2013-09-06 12:47:41 -0400
commit99d5040ebc3cccc90dfe031f615ac3fbc79905b6 (patch)
tree04d720df138145f5cb4efd4cf4358c88d44b19d3 /arch/xtensa
parent16c5becf39a2d174f08b46504f522c2fa50ef462 (diff)
xtensa: keep a3 and excsave1 on entry to exception handlers
Based on the SMP patch by Joe Taylor and subsequent fixes. Preserve exception table pointer (normally stored in excsave1 SR) as it cannot be easily restored in SMP environment. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Chris Zankel <chris@zankel.net>
Diffstat (limited to 'arch/xtensa')
-rw-r--r--arch/xtensa/include/asm/regs.h1
-rw-r--r--arch/xtensa/kernel/align.S5
-rw-r--r--arch/xtensa/kernel/coprocessor.S9
-rw-r--r--arch/xtensa/kernel/entry.S115
-rw-r--r--arch/xtensa/kernel/vectors.S250
5 files changed, 238 insertions, 142 deletions
diff --git a/arch/xtensa/include/asm/regs.h b/arch/xtensa/include/asm/regs.h
index b24de6717020..4ba9f516b0e2 100644
--- a/arch/xtensa/include/asm/regs.h
+++ b/arch/xtensa/include/asm/regs.h
@@ -82,6 +82,7 @@
82#define PS_CALLINC_SHIFT 16 82#define PS_CALLINC_SHIFT 16
83#define PS_CALLINC_MASK 0x00030000 83#define PS_CALLINC_MASK 0x00030000
84#define PS_OWB_SHIFT 8 84#define PS_OWB_SHIFT 8
85#define PS_OWB_WIDTH 4
85#define PS_OWB_MASK 0x00000F00 86#define PS_OWB_MASK 0x00000F00
86#define PS_RING_SHIFT 6 87#define PS_RING_SHIFT 6
87#define PS_RING_MASK 0x000000C0 88#define PS_RING_MASK 0x000000C0
diff --git a/arch/xtensa/kernel/align.S b/arch/xtensa/kernel/align.S
index aa2e87b8566a..d4cef6039a5c 100644
--- a/arch/xtensa/kernel/align.S
+++ b/arch/xtensa/kernel/align.S
@@ -146,9 +146,9 @@
146 * a0: trashed, original value saved on stack (PT_AREG0) 146 * a0: trashed, original value saved on stack (PT_AREG0)
147 * a1: a1 147 * a1: a1
148 * a2: new stack pointer, original in DEPC 148 * a2: new stack pointer, original in DEPC
149 * a3: dispatch table 149 * a3: a3
150 * depc: a2, original value saved on stack (PT_DEPC) 150 * depc: a2, original value saved on stack (PT_DEPC)
151 * excsave_1: a3 151 * excsave_1: dispatch table
152 * 152 *
153 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 153 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
154 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 154 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -171,7 +171,6 @@ ENTRY(fast_unaligned)
171 s32i a8, a2, PT_AREG8 171 s32i a8, a2, PT_AREG8
172 172
173 rsr a0, depc 173 rsr a0, depc
174 xsr a3, excsave1
175 s32i a0, a2, PT_AREG2 174 s32i a0, a2, PT_AREG2
176 s32i a3, a2, PT_AREG3 175 s32i a3, a2, PT_AREG3
177 176
diff --git a/arch/xtensa/kernel/coprocessor.S b/arch/xtensa/kernel/coprocessor.S
index 647657484866..a482df5df2b2 100644
--- a/arch/xtensa/kernel/coprocessor.S
+++ b/arch/xtensa/kernel/coprocessor.S
@@ -32,9 +32,9 @@
32 * a0: trashed, original value saved on stack (PT_AREG0) 32 * a0: trashed, original value saved on stack (PT_AREG0)
33 * a1: a1 33 * a1: a1
34 * a2: new stack pointer, original in DEPC 34 * a2: new stack pointer, original in DEPC
35 * a3: dispatch table 35 * a3: a3
36 * depc: a2, original value saved on stack (PT_DEPC) 36 * depc: a2, original value saved on stack (PT_DEPC)
37 * excsave_1: a3 37 * excsave_1: dispatch table
38 * 38 *
39 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 39 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
40 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 40 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -225,9 +225,9 @@ ENDPROC(coprocessor_restore)
225 * a0: trashed, original value saved on stack (PT_AREG0) 225 * a0: trashed, original value saved on stack (PT_AREG0)
226 * a1: a1 226 * a1: a1
227 * a2: new stack pointer, original in DEPC 227 * a2: new stack pointer, original in DEPC
228 * a3: dispatch table 228 * a3: a3
229 * depc: a2, original value saved on stack (PT_DEPC) 229 * depc: a2, original value saved on stack (PT_DEPC)
230 * excsave_1: a3 230 * excsave_1: dispatch table
231 * 231 *
232 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 232 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
233 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 233 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -245,7 +245,6 @@ ENTRY(fast_coprocessor)
245 245
246 /* Save remaining registers a1-a3 and SAR */ 246 /* Save remaining registers a1-a3 and SAR */
247 247
248 xsr a3, excsave1
249 s32i a3, a2, PT_AREG3 248 s32i a3, a2, PT_AREG3
250 rsr a3, sar 249 rsr a3, sar
251 s32i a1, a2, PT_AREG1 250 s32i a1, a2, PT_AREG1
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 3f3de283d707..ab025c1f6e23 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -91,9 +91,9 @@
91 * a0: trashed, original value saved on stack (PT_AREG0) 91 * a0: trashed, original value saved on stack (PT_AREG0)
92 * a1: a1 92 * a1: a1
93 * a2: new stack pointer, original value in depc 93 * a2: new stack pointer, original value in depc
94 * a3: dispatch table 94 * a3: a3
95 * depc: a2, original value saved on stack (PT_DEPC) 95 * depc: a2, original value saved on stack (PT_DEPC)
96 * excsave1: a3 96 * excsave1: dispatch table
97 * 97 *
98 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 98 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
99 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 99 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -109,9 +109,8 @@
109 109
110ENTRY(user_exception) 110ENTRY(user_exception)
111 111
112 /* Save a2, a3, and depc, restore excsave_1 and set SP. */ 112 /* Save a1, a2, a3, and set SP. */
113 113
114 xsr a3, excsave1
115 rsr a0, depc 114 rsr a0, depc
116 s32i a1, a2, PT_AREG1 115 s32i a1, a2, PT_AREG1
117 s32i a0, a2, PT_AREG2 116 s32i a0, a2, PT_AREG2
@@ -237,9 +236,9 @@ ENDPROC(user_exception)
237 * a0: trashed, original value saved on stack (PT_AREG0) 236 * a0: trashed, original value saved on stack (PT_AREG0)
238 * a1: a1 237 * a1: a1
239 * a2: new stack pointer, original in DEPC 238 * a2: new stack pointer, original in DEPC
240 * a3: dispatch table 239 * a3: a3
241 * depc: a2, original value saved on stack (PT_DEPC) 240 * depc: a2, original value saved on stack (PT_DEPC)
242 * excsave_1: a3 241 * excsave_1: dispatch table
243 * 242 *
244 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 243 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
245 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 244 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -255,9 +254,8 @@ ENDPROC(user_exception)
255 254
256ENTRY(kernel_exception) 255ENTRY(kernel_exception)
257 256
258 /* Save a0, a2, a3, DEPC and set SP. */ 257 /* Save a1, a2, a3, and set SP. */
259 258
260 xsr a3, excsave1 # restore a3, excsave_1
261 rsr a0, depc # get a2 259 rsr a0, depc # get a2
262 s32i a1, a2, PT_AREG1 260 s32i a1, a2, PT_AREG1
263 s32i a0, a2, PT_AREG2 261 s32i a0, a2, PT_AREG2
@@ -408,7 +406,7 @@ common_exception:
408 * exception handler and call the exception handler. 406 * exception handler and call the exception handler.
409 */ 407 */
410 408
411 movi a4, exc_table 409 rsr a4, excsave1
412 mov a6, a1 # pass stack frame 410 mov a6, a1 # pass stack frame
413 mov a7, a0 # pass EXCCAUSE 411 mov a7, a0 # pass EXCCAUSE
414 addx4 a4, a0, a4 412 addx4 a4, a0, a4
@@ -832,9 +830,9 @@ ENDPROC(unrecoverable_exception)
832 * a0: trashed, original value saved on stack (PT_AREG0) 830 * a0: trashed, original value saved on stack (PT_AREG0)
833 * a1: a1 831 * a1: a1
834 * a2: new stack pointer, original in DEPC 832 * a2: new stack pointer, original in DEPC
835 * a3: dispatch table 833 * a3: a3
836 * depc: a2, original value saved on stack (PT_DEPC) 834 * depc: a2, original value saved on stack (PT_DEPC)
837 * excsave_1: a3 835 * excsave_1: dispatch table
838 * 836 *
839 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 837 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
840 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 838 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -857,18 +855,16 @@ ENTRY(fast_alloca)
857 855
858 rsr a0, depc # get a2 856 rsr a0, depc # get a2
859 s32i a4, a2, PT_AREG4 # save a4 and 857 s32i a4, a2, PT_AREG4 # save a4 and
858 s32i a3, a2, PT_AREG3
860 s32i a0, a2, PT_AREG2 # a2 to stack 859 s32i a0, a2, PT_AREG2 # a2 to stack
861 860
862 /* Exit critical section. */ 861 /* Exit critical section. */
863 862
864 movi a0, 0 863 movi a0, 0
864 rsr a3, excsave1
865 s32i a0, a3, EXC_TABLE_FIXUP 865 s32i a0, a3, EXC_TABLE_FIXUP
866 866
867 /* Restore a3, excsave_1 */
868
869 xsr a3, excsave1 # make sure excsave_1 is valid for dbl.
870 rsr a4, epc1 # get exception address 867 rsr a4, epc1 # get exception address
871 s32i a3, a2, PT_AREG3 # save a3 to stack
872 868
873#ifdef ALLOCA_EXCEPTION_IN_IRAM 869#ifdef ALLOCA_EXCEPTION_IN_IRAM
874#error iram not supported 870#error iram not supported
@@ -1007,9 +1003,9 @@ ENDPROC(fast_alloca)
1007 * a0: trashed, original value saved on stack (PT_AREG0) 1003 * a0: trashed, original value saved on stack (PT_AREG0)
1008 * a1: a1 1004 * a1: a1
1009 * a2: new stack pointer, original in DEPC 1005 * a2: new stack pointer, original in DEPC
1010 * a3: dispatch table 1006 * a3: a3
1011 * depc: a2, original value saved on stack (PT_DEPC) 1007 * depc: a2, original value saved on stack (PT_DEPC)
1012 * excsave_1: a3 1008 * excsave_1: dispatch table
1013 */ 1009 */
1014 1010
1015ENTRY(fast_syscall_kernel) 1011ENTRY(fast_syscall_kernel)
@@ -1056,7 +1052,6 @@ ENTRY(fast_syscall_unrecoverable)
1056 1052
1057 l32i a0, a2, PT_AREG0 # restore a0 1053 l32i a0, a2, PT_AREG0 # restore a0
1058 xsr a2, depc # restore a2, depc 1054 xsr a2, depc # restore a2, depc
1059 rsr a3, excsave1
1060 1055
1061 wsr a0, excsave1 1056 wsr a0, excsave1
1062 movi a0, unrecoverable_exception 1057 movi a0, unrecoverable_exception
@@ -1078,10 +1073,10 @@ ENDPROC(fast_syscall_unrecoverable)
1078 * a0: a2 (syscall-nr), original value saved on stack (PT_AREG0) 1073 * a0: a2 (syscall-nr), original value saved on stack (PT_AREG0)
1079 * a1: a1 1074 * a1: a1
1080 * a2: new stack pointer, original in a0 and DEPC 1075 * a2: new stack pointer, original in a0 and DEPC
1081 * a3: dispatch table, original in excsave_1 1076 * a3: a3
1082 * a4..a15: unchanged 1077 * a4..a15: unchanged
1083 * depc: a2, original value saved on stack (PT_DEPC) 1078 * depc: a2, original value saved on stack (PT_DEPC)
1084 * excsave_1: a3 1079 * excsave_1: dispatch table
1085 * 1080 *
1086 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 1081 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
1087 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 1082 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -1114,8 +1109,6 @@ ENDPROC(fast_syscall_unrecoverable)
1114 1109
1115ENTRY(fast_syscall_xtensa) 1110ENTRY(fast_syscall_xtensa)
1116 1111
1117 xsr a3, excsave1 # restore a3, excsave1
1118
1119 s32i a7, a2, PT_AREG7 # we need an additional register 1112 s32i a7, a2, PT_AREG7 # we need an additional register
1120 movi a7, 4 # sizeof(unsigned int) 1113 movi a7, 4 # sizeof(unsigned int)
1121 access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp 1114 access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp
@@ -1178,9 +1171,9 @@ ENDPROC(fast_syscall_xtensa)
1178 * a0: trashed, original value saved on stack (PT_AREG0) 1171 * a0: trashed, original value saved on stack (PT_AREG0)
1179 * a1: a1 1172 * a1: a1
1180 * a2: new stack pointer, original in DEPC 1173 * a2: new stack pointer, original in DEPC
1181 * a3: dispatch table 1174 * a3: a3
1182 * depc: a2, original value saved on stack (PT_DEPC) 1175 * depc: a2, original value saved on stack (PT_DEPC)
1183 * excsave_1: a3 1176 * excsave_1: dispatch table
1184 * 1177 *
1185 * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler. 1178 * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler.
1186 */ 1179 */
@@ -1189,15 +1182,16 @@ ENTRY(fast_syscall_spill_registers)
1189 1182
1190 /* Register a FIXUP handler (pass current wb as a parameter) */ 1183 /* Register a FIXUP handler (pass current wb as a parameter) */
1191 1184
1185 xsr a3, excsave1
1192 movi a0, fast_syscall_spill_registers_fixup 1186 movi a0, fast_syscall_spill_registers_fixup
1193 s32i a0, a3, EXC_TABLE_FIXUP 1187 s32i a0, a3, EXC_TABLE_FIXUP
1194 rsr a0, windowbase 1188 rsr a0, windowbase
1195 s32i a0, a3, EXC_TABLE_PARAM 1189 s32i a0, a3, EXC_TABLE_PARAM
1190 xsr a3, excsave1 # restore a3 and excsave_1
1196 1191
1197 /* Save a3 and SAR on stack. */ 1192 /* Save a3, a4 and SAR on stack. */
1198 1193
1199 rsr a0, sar 1194 rsr a0, sar
1200 xsr a3, excsave1 # restore a3 and excsave_1
1201 s32i a3, a2, PT_AREG3 1195 s32i a3, a2, PT_AREG3
1202 s32i a4, a2, PT_AREG4 1196 s32i a4, a2, PT_AREG4
1203 s32i a0, a2, PT_AREG5 # store SAR to PT_AREG5 1197 s32i a0, a2, PT_AREG5 # store SAR to PT_AREG5
@@ -1251,14 +1245,14 @@ fast_syscall_spill_registers_fixup:
1251 * in WS, so that the exception handlers save them to the task stack. 1245 * in WS, so that the exception handlers save them to the task stack.
1252 */ 1246 */
1253 1247
1254 rsr a3, excsave1 # get spill-mask 1248 xsr a3, excsave1 # get spill-mask
1255 slli a2, a3, 1 # shift left by one 1249 slli a2, a3, 1 # shift left by one
1256 1250
1257 slli a3, a2, 32-WSBITS 1251 slli a3, a2, 32-WSBITS
1258 src a2, a2, a3 # a1 = xxwww1yyxxxwww1yy...... 1252 src a2, a2, a3 # a1 = xxwww1yyxxxwww1yy......
1259 wsr a2, windowstart # set corrected windowstart 1253 wsr a2, windowstart # set corrected windowstart
1260 1254
1261 movi a3, exc_table 1255 rsr a3, excsave1
1262 l32i a2, a3, EXC_TABLE_DOUBLE_SAVE # restore a2 1256 l32i a2, a3, EXC_TABLE_DOUBLE_SAVE # restore a2
1263 l32i a3, a3, EXC_TABLE_PARAM # original WB (in user task) 1257 l32i a3, a3, EXC_TABLE_PARAM # original WB (in user task)
1264 1258
@@ -1295,7 +1289,7 @@ fast_syscall_spill_registers_fixup:
1295 1289
1296 /* Jump to the exception handler. */ 1290 /* Jump to the exception handler. */
1297 1291
1298 movi a3, exc_table 1292 rsr a3, excsave1
1299 rsr a0, exccause 1293 rsr a0, exccause
1300 addx4 a0, a0, a3 # find entry in table 1294 addx4 a0, a0, a3 # find entry in table
1301 l32i a0, a0, EXC_TABLE_FAST_USER # load handler 1295 l32i a0, a0, EXC_TABLE_FAST_USER # load handler
@@ -1312,6 +1306,7 @@ fast_syscall_spill_registers_fixup_return:
1312 xsr a3, excsave1 1306 xsr a3, excsave1
1313 movi a2, fast_syscall_spill_registers_fixup 1307 movi a2, fast_syscall_spill_registers_fixup
1314 s32i a2, a3, EXC_TABLE_FIXUP 1308 s32i a2, a3, EXC_TABLE_FIXUP
1309 s32i a0, a3, EXC_TABLE_DOUBLE_SAVE
1315 rsr a2, windowbase 1310 rsr a2, windowbase
1316 s32i a2, a3, EXC_TABLE_PARAM 1311 s32i a2, a3, EXC_TABLE_PARAM
1317 l32i a2, a3, EXC_TABLE_KSTK 1312 l32i a2, a3, EXC_TABLE_KSTK
@@ -1323,11 +1318,6 @@ fast_syscall_spill_registers_fixup_return:
1323 wsr a3, windowbase 1318 wsr a3, windowbase
1324 rsync 1319 rsync
1325 1320
1326 /* Restore a3 and return. */
1327
1328 movi a3, exc_table
1329 xsr a3, excsave1
1330
1331 rfde 1321 rfde
1332 1322
1333 1323
@@ -1514,9 +1504,8 @@ ENTRY(_spill_registers)
1514 1504
1515 movi a0, 0 1505 movi a0, 0
1516 1506
1517 movi a3, exc_table 1507 rsr a3, excsave1
1518 l32i a1, a3, EXC_TABLE_KSTK 1508 l32i a1, a3, EXC_TABLE_KSTK
1519 wsr a3, excsave1
1520 1509
1521 movi a4, (1 << PS_WOE_BIT) | LOCKLEVEL 1510 movi a4, (1 << PS_WOE_BIT) | LOCKLEVEL
1522 wsr a4, ps 1511 wsr a4, ps
@@ -1560,9 +1549,9 @@ ENDPROC(fast_second_level_miss_double_kernel)
1560 * a0: trashed, original value saved on stack (PT_AREG0) 1549 * a0: trashed, original value saved on stack (PT_AREG0)
1561 * a1: a1 1550 * a1: a1
1562 * a2: new stack pointer, original in DEPC 1551 * a2: new stack pointer, original in DEPC
1563 * a3: dispatch table 1552 * a3: a3
1564 * depc: a2, original value saved on stack (PT_DEPC) 1553 * depc: a2, original value saved on stack (PT_DEPC)
1565 * excsave_1: a3 1554 * excsave_1: dispatch table
1566 * 1555 *
1567 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 1556 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
1568 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 1557 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -1570,9 +1559,10 @@ ENDPROC(fast_second_level_miss_double_kernel)
1570 1559
1571ENTRY(fast_second_level_miss) 1560ENTRY(fast_second_level_miss)
1572 1561
1573 /* Save a1. Note: we don't expect a double exception. */ 1562 /* Save a1 and a3. Note: we don't expect a double exception. */
1574 1563
1575 s32i a1, a2, PT_AREG1 1564 s32i a1, a2, PT_AREG1
1565 s32i a3, a2, PT_AREG3
1576 1566
1577 /* We need to map the page of PTEs for the user task. Find 1567 /* We need to map the page of PTEs for the user task. Find
1578 * the pointer to that page. Also, it's possible for tsk->mm 1568 * the pointer to that page. Also, it's possible for tsk->mm
@@ -1594,9 +1584,6 @@ ENTRY(fast_second_level_miss)
1594 l32i a0, a1, TASK_MM # tsk->mm 1584 l32i a0, a1, TASK_MM # tsk->mm
1595 beqz a0, 9f 1585 beqz a0, 9f
1596 1586
1597
1598 /* We deliberately destroy a3 that holds the exception table. */
1599
16008: rsr a3, excvaddr # fault address 15878: rsr a3, excvaddr # fault address
1601 _PGD_OFFSET(a0, a3, a1) 1588 _PGD_OFFSET(a0, a3, a1)
1602 l32i a0, a0, 0 # read pmdval 1589 l32i a0, a0, 0 # read pmdval
@@ -1647,7 +1634,7 @@ ENTRY(fast_second_level_miss)
1647 1634
1648 /* Exit critical section. */ 1635 /* Exit critical section. */
1649 1636
16504: movi a3, exc_table # restore a3 16374: rsr a3, excsave1
1651 movi a0, 0 1638 movi a0, 0
1652 s32i a0, a3, EXC_TABLE_FIXUP 1639 s32i a0, a3, EXC_TABLE_FIXUP
1653 1640
@@ -1655,8 +1642,8 @@ ENTRY(fast_second_level_miss)
1655 1642
1656 l32i a0, a2, PT_AREG0 1643 l32i a0, a2, PT_AREG0
1657 l32i a1, a2, PT_AREG1 1644 l32i a1, a2, PT_AREG1
1645 l32i a3, a2, PT_AREG3
1658 l32i a2, a2, PT_DEPC 1646 l32i a2, a2, PT_DEPC
1659 xsr a3, excsave1
1660 1647
1661 bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f 1648 bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
1662 1649
@@ -1743,11 +1730,8 @@ ENTRY(fast_second_level_miss)
1743 1730
17442: /* Invalid PGD, default exception handling */ 17312: /* Invalid PGD, default exception handling */
1745 1732
1746 movi a3, exc_table
1747 rsr a1, depc 1733 rsr a1, depc
1748 xsr a3, excsave1
1749 s32i a1, a2, PT_AREG2 1734 s32i a1, a2, PT_AREG2
1750 s32i a3, a2, PT_AREG3
1751 mov a1, a2 1735 mov a1, a2
1752 1736
1753 rsr a2, ps 1737 rsr a2, ps
@@ -1767,9 +1751,9 @@ ENDPROC(fast_second_level_miss)
1767 * a0: trashed, original value saved on stack (PT_AREG0) 1751 * a0: trashed, original value saved on stack (PT_AREG0)
1768 * a1: a1 1752 * a1: a1
1769 * a2: new stack pointer, original in DEPC 1753 * a2: new stack pointer, original in DEPC
1770 * a3: dispatch table 1754 * a3: a3
1771 * depc: a2, original value saved on stack (PT_DEPC) 1755 * depc: a2, original value saved on stack (PT_DEPC)
1772 * excsave_1: a3 1756 * excsave_1: dispatch table
1773 * 1757 *
1774 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC 1758 * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
1775 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception 1759 * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -1777,17 +1761,17 @@ ENDPROC(fast_second_level_miss)
1777 1761
1778ENTRY(fast_store_prohibited) 1762ENTRY(fast_store_prohibited)
1779 1763
1780 /* Save a1 and a4. */ 1764 /* Save a1 and a3. */
1781 1765
1782 s32i a1, a2, PT_AREG1 1766 s32i a1, a2, PT_AREG1
1783 s32i a4, a2, PT_AREG4 1767 s32i a3, a2, PT_AREG3
1784 1768
1785 GET_CURRENT(a1,a2) 1769 GET_CURRENT(a1,a2)
1786 l32i a0, a1, TASK_MM # tsk->mm 1770 l32i a0, a1, TASK_MM # tsk->mm
1787 beqz a0, 9f 1771 beqz a0, 9f
1788 1772
17898: rsr a1, excvaddr # fault address 17738: rsr a1, excvaddr # fault address
1790 _PGD_OFFSET(a0, a1, a4) 1774 _PGD_OFFSET(a0, a1, a3)
1791 l32i a0, a0, 0 1775 l32i a0, a0, 0
1792 beqz a0, 2f 1776 beqz a0, 2f
1793 1777
@@ -1796,39 +1780,37 @@ ENTRY(fast_store_prohibited)
1796 * and is not PAGE_NONE. See pgtable.h for possible PTE layouts. 1780 * and is not PAGE_NONE. See pgtable.h for possible PTE layouts.
1797 */ 1781 */
1798 1782
1799 _PTE_OFFSET(a0, a1, a4) 1783 _PTE_OFFSET(a0, a1, a3)
1800 l32i a4, a0, 0 # read pteval 1784 l32i a3, a0, 0 # read pteval
1801 movi a1, _PAGE_CA_INVALID 1785 movi a1, _PAGE_CA_INVALID
1802 ball a4, a1, 2f 1786 ball a3, a1, 2f
1803 bbci.l a4, _PAGE_WRITABLE_BIT, 2f 1787 bbci.l a3, _PAGE_WRITABLE_BIT, 2f
1804 1788
1805 movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE 1789 movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE
1806 or a4, a4, a1 1790 or a3, a3, a1
1807 rsr a1, excvaddr 1791 rsr a1, excvaddr
1808 s32i a4, a0, 0 1792 s32i a3, a0, 0
1809 1793
1810 /* We need to flush the cache if we have page coloring. */ 1794 /* We need to flush the cache if we have page coloring. */
1811#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK 1795#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
1812 dhwb a0, 0 1796 dhwb a0, 0
1813#endif 1797#endif
1814 pdtlb a0, a1 1798 pdtlb a0, a1
1815 wdtlb a4, a0 1799 wdtlb a3, a0
1816 1800
1817 /* Exit critical section. */ 1801 /* Exit critical section. */
1818 1802
1819 movi a0, 0 1803 movi a0, 0
1804 rsr a3, excsave1
1820 s32i a0, a3, EXC_TABLE_FIXUP 1805 s32i a0, a3, EXC_TABLE_FIXUP
1821 1806
1822 /* Restore the working registers, and return. */ 1807 /* Restore the working registers, and return. */
1823 1808
1824 l32i a4, a2, PT_AREG4 1809 l32i a3, a2, PT_AREG3
1825 l32i a1, a2, PT_AREG1 1810 l32i a1, a2, PT_AREG1
1826 l32i a0, a2, PT_AREG0 1811 l32i a0, a2, PT_AREG0
1827 l32i a2, a2, PT_DEPC 1812 l32i a2, a2, PT_DEPC
1828 1813
1829 /* Restore excsave1 and a3. */
1830
1831 xsr a3, excsave1
1832 bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f 1814 bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
1833 1815
1834 rsr a2, depc 1816 rsr a2, depc
@@ -1845,11 +1827,8 @@ ENTRY(fast_store_prohibited)
1845 1827
18462: /* If there was a problem, handle fault in C */ 18282: /* If there was a problem, handle fault in C */
1847 1829
1848 rsr a4, depc # still holds a2 1830 rsr a3, depc # still holds a2
1849 xsr a3, excsave1 1831 s32i a3, a2, PT_AREG2
1850 s32i a4, a2, PT_AREG2
1851 s32i a3, a2, PT_AREG3
1852 l32i a4, a2, PT_AREG4
1853 mov a1, a2 1832 mov a1, a2
1854 1833
1855 rsr a2, ps 1834 rsr a2, ps
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S
index f9e175382aa9..cb8fd44caabc 100644
--- a/arch/xtensa/kernel/vectors.S
+++ b/arch/xtensa/kernel/vectors.S
@@ -78,6 +78,7 @@ ENTRY(_UserExceptionVector)
78 s32i a0, a2, PT_DEPC # mark it as a regular exception 78 s32i a0, a2, PT_DEPC # mark it as a regular exception
79 addx4 a0, a0, a3 # find entry in table 79 addx4 a0, a0, a3 # find entry in table
80 l32i a0, a0, EXC_TABLE_FAST_USER # load handler 80 l32i a0, a0, EXC_TABLE_FAST_USER # load handler
81 xsr a3, excsave1 # restore a3 and dispatch table
81 jx a0 82 jx a0
82 83
83ENDPROC(_UserExceptionVector) 84ENDPROC(_UserExceptionVector)
@@ -104,6 +105,7 @@ ENTRY(_KernelExceptionVector)
104 s32i a0, a2, PT_DEPC # mark it as a regular exception 105 s32i a0, a2, PT_DEPC # mark it as a regular exception
105 addx4 a0, a0, a3 # find entry in table 106 addx4 a0, a0, a3 # find entry in table
106 l32i a0, a0, EXC_TABLE_FAST_KERNEL # load handler address 107 l32i a0, a0, EXC_TABLE_FAST_KERNEL # load handler address
108 xsr a3, excsave1 # restore a3 and dispatch table
107 jx a0 109 jx a0
108 110
109ENDPROC(_KernelExceptionVector) 111ENDPROC(_KernelExceptionVector)
@@ -168,7 +170,7 @@ ENDPROC(_KernelExceptionVector)
168 * 170 *
169 * a0: DEPC 171 * a0: DEPC
170 * a1: a1 172 * a1: a1
171 * a2: trashed, original value in EXC_TABLE_DOUBLE_A2 173 * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
172 * a3: exctable 174 * a3: exctable
173 * depc: a0 175 * depc: a0
174 * excsave_1: a3 176 * excsave_1: a3
@@ -204,47 +206,46 @@ ENDPROC(_KernelExceptionVector)
204 206
205 .section .DoubleExceptionVector.text, "ax" 207 .section .DoubleExceptionVector.text, "ax"
206 .begin literal_prefix .DoubleExceptionVector 208 .begin literal_prefix .DoubleExceptionVector
209 .globl _DoubleExceptionVector_WindowUnderflow
210 .globl _DoubleExceptionVector_WindowOverflow
207 211
208ENTRY(_DoubleExceptionVector) 212ENTRY(_DoubleExceptionVector)
209 213
210 /* Deliberately destroy excsave (don't assume it's value was valid). */ 214 xsr a3, excsave1
211 215 s32i a2, a3, EXC_TABLE_DOUBLE_SAVE
212 wsr a3, excsave1 # save a3
213 216
214 /* Check for kernel double exception (usually fatal). */ 217 /* Check for kernel double exception (usually fatal). */
215 218
216 rsr a3, ps 219 rsr a2, ps
217 _bbci.l a3, PS_UM_BIT, .Lksp 220 _bbci.l a2, PS_UM_BIT, .Lksp
218 221
219 /* Check if we are currently handling a window exception. */ 222 /* Check if we are currently handling a window exception. */
220 /* Note: We don't need to indicate that we enter a critical section. */ 223 /* Note: We don't need to indicate that we enter a critical section. */
221 224
222 xsr a0, depc # get DEPC, save a0 225 xsr a0, depc # get DEPC, save a0
223 226
224 movi a3, WINDOW_VECTORS_VADDR 227 movi a2, WINDOW_VECTORS_VADDR
225 _bltu a0, a3, .Lfixup 228 _bltu a0, a2, .Lfixup
226 addi a3, a3, WINDOW_VECTORS_SIZE 229 addi a2, a2, WINDOW_VECTORS_SIZE
227 _bgeu a0, a3, .Lfixup 230 _bgeu a0, a2, .Lfixup
228 231
229 /* Window overflow/underflow exception. Get stack pointer. */ 232 /* Window overflow/underflow exception. Get stack pointer. */
230 233
231 mov a3, a2 234 l32i a2, a3, EXC_TABLE_KSTK
232 /* This explicit literal and the following references to it are made
233 * in order to fit DoubleExceptionVector.literals into the available
234 * 16-byte gap before DoubleExceptionVector.text in the absence of
235 * link time relaxation. See kernel/vmlinux.lds.S
236 */
237 .literal .Lexc_table, exc_table
238 l32r a2, .Lexc_table
239 l32i a2, a2, EXC_TABLE_KSTK
240 235
241 /* Check for overflow/underflow exception, jump if overflow. */ 236 /* Check for overflow/underflow exception, jump if overflow. */
242 237
243 _bbci.l a0, 6, .Lovfl 238 _bbci.l a0, 6, _DoubleExceptionVector_WindowOverflow
244
245 /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */
246 239
247 /* Restart window underflow exception. 240 /*
241 * Restart window underflow exception.
242 * Currently:
243 * depc = orig a0,
244 * a0 = orig DEPC,
245 * a2 = new sp based on KSTK from exc_table
246 * a3 = excsave_1
247 * excsave_1 = orig a3
248 *
248 * We return to the instruction in user space that caused the window 249 * We return to the instruction in user space that caused the window
249 * underflow exception. Therefore, we change window base to the value 250 * underflow exception. Therefore, we change window base to the value
250 * before we entered the window underflow exception and prepare the 251 * before we entered the window underflow exception and prepare the
@@ -252,10 +253,11 @@ ENTRY(_DoubleExceptionVector)
252 * by changing depc (in a0). 253 * by changing depc (in a0).
253 * Note: We can trash the current window frame (a0...a3) and depc! 254 * Note: We can trash the current window frame (a0...a3) and depc!
254 */ 255 */
255 256_DoubleExceptionVector_WindowUnderflow:
257 xsr a3, excsave1
256 wsr a2, depc # save stack pointer temporarily 258 wsr a2, depc # save stack pointer temporarily
257 rsr a0, ps 259 rsr a0, ps
258 extui a0, a0, PS_OWB_SHIFT, 4 260 extui a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
259 wsr a0, windowbase 261 wsr a0, windowbase
260 rsync 262 rsync
261 263
@@ -263,28 +265,57 @@ ENTRY(_DoubleExceptionVector)
263 265
264 xsr a2, depc # save a2 and get stack pointer 266 xsr a2, depc # save a2 and get stack pointer
265 s32i a0, a2, PT_AREG0 267 s32i a0, a2, PT_AREG0
266 268 xsr a3, excsave1
267 wsr a3, excsave1 # save a3
268 l32r a3, .Lexc_table
269
270 rsr a0, exccause 269 rsr a0, exccause
271 s32i a0, a2, PT_DEPC # mark it as a regular exception 270 s32i a0, a2, PT_DEPC # mark it as a regular exception
272 addx4 a0, a0, a3 271 addx4 a0, a0, a3
272 xsr a3, excsave1
273 l32i a0, a0, EXC_TABLE_FAST_USER 273 l32i a0, a0, EXC_TABLE_FAST_USER
274 jx a0 274 jx a0
275 275
276.Lfixup:/* Check for a fixup handler or if we were in a critical section. */ 276 /*
277 * We only allow the ITLB miss exception if we are in kernel space.
278 * All other exceptions are unexpected and thus unrecoverable!
279 */
280
281#ifdef CONFIG_MMU
282 .extern fast_second_level_miss_double_kernel
283
284.Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
285
286 rsr a3, exccause
287 beqi a3, EXCCAUSE_ITLB_MISS, 1f
288 addi a3, a3, -EXCCAUSE_DTLB_MISS
289 bnez a3, .Lunrecoverable
2901: movi a3, fast_second_level_miss_double_kernel
291 jx a3
292#else
293.equ .Lksp, .Lunrecoverable
294#endif
295
296 /* Critical! We can't handle this situation. PANIC! */
277 297
278 /* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */ 298 .extern unrecoverable_exception
279 299
280 l32r a3, .Lexc_table 300.Lunrecoverable_fixup:
281 s32i a2, a3, EXC_TABLE_DOUBLE_SAVE # temporary variable 301 l32i a2, a3, EXC_TABLE_DOUBLE_SAVE
302 xsr a0, depc
303
304.Lunrecoverable:
305 rsr a3, excsave1
306 wsr a0, excsave1
307 movi a0, unrecoverable_exception
308 callx0 a0
309
310.Lfixup:/* Check for a fixup handler or if we were in a critical section. */
311
312 /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave1: a3 */
282 313
283 /* Enter critical section. */ 314 /* Enter critical section. */
284 315
285 l32i a2, a3, EXC_TABLE_FIXUP 316 l32i a2, a3, EXC_TABLE_FIXUP
286 s32i a3, a3, EXC_TABLE_FIXUP 317 s32i a3, a3, EXC_TABLE_FIXUP
287 beq a2, a3, .Lunrecoverable_fixup # critical! 318 beq a2, a3, .Lunrecoverable_fixup # critical section
288 beqz a2, .Ldflt # no handler was registered 319 beqz a2, .Ldflt # no handler was registered
289 320
290 /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */ 321 /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */
@@ -293,58 +324,145 @@ ENTRY(_DoubleExceptionVector)
293 324
294.Ldflt: /* Get stack pointer. */ 325.Ldflt: /* Get stack pointer. */
295 326
296 l32i a3, a3, EXC_TABLE_DOUBLE_SAVE 327 l32i a2, a3, EXC_TABLE_DOUBLE_SAVE
297 addi a2, a3, -PT_USER_SIZE 328 addi a2, a2, -PT_USER_SIZE
298
299.Lovfl: /* Jump to default handlers. */
300 329
301 /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */ 330 /* a0: depc, a1: a1, a2: kstk, a3: exctable, depc: a0, excsave: a3 */
302 331
303 xsr a3, depc
304 s32i a0, a2, PT_DEPC 332 s32i a0, a2, PT_DEPC
305 s32i a3, a2, PT_AREG0 333 l32i a0, a3, EXC_TABLE_DOUBLE_SAVE
334 xsr a0, depc
335 s32i a0, a2, PT_AREG0
306 336
307 /* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */ 337 /* a0: avail, a1: a1, a2: kstk, a3: exctable, depc: a2, excsave: a3 */
308 338
309 l32r a3, .Lexc_table
310 rsr a0, exccause 339 rsr a0, exccause
311 addx4 a0, a0, a3 340 addx4 a0, a0, a3
341 xsr a3, excsave1
312 l32i a0, a0, EXC_TABLE_FAST_USER 342 l32i a0, a0, EXC_TABLE_FAST_USER
313 jx a0 343 jx a0
314 344
315 /* 345 /*
316 * We only allow the ITLB miss exception if we are in kernel space. 346 * Restart window OVERFLOW exception.
317 * All other exceptions are unexpected and thus unrecoverable! 347 * Currently:
348 * depc = orig a0,
349 * a0 = orig DEPC,
350 * a2 = new sp based on KSTK from exc_table
351 * a3 = EXCSAVE_1
352 * excsave_1 = orig a3
353 *
354 * We return to the instruction in user space that caused the window
355 * overflow exception. Therefore, we change window base to the value
356 * before we entered the window overflow exception and prepare the
357 * registers to return as if we were coming from a regular exception
358 * by changing DEPC (in a0).
359 *
360 * NOTE: We CANNOT trash the current window frame (a0...a3), but we
361 * can clobber depc.
362 *
363 * The tricky part here is that overflow8 and overflow12 handlers
364 * save a0, then clobber a0. To restart the handler, we have to restore
365 * a0 if the double exception was past the point where a0 was clobbered.
366 *
367 * To keep things simple, we take advantage of the fact all overflow
368 * handlers save a0 in their very first instruction. If DEPC was past
369 * that instruction, we can safely restore a0 from where it was saved
370 * on the stack.
371 *
372 * a0: depc, a1: a1, a2: kstk, a3: exc_table, depc: a0, excsave1: a3
318 */ 373 */
374_DoubleExceptionVector_WindowOverflow:
375 extui a2, a0, 0, 6 # get offset into 64-byte vector handler
376 beqz a2, 1f # if at start of vector, don't restore
319 377
320#ifdef CONFIG_MMU 378 addi a0, a0, -128
321 .extern fast_second_level_miss_double_kernel 379 bbsi a0, 8, 1f # don't restore except for overflow 8 and 12
380 bbsi a0, 7, 2f
322 381
323.Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */ 382 /*
383 * Restore a0 as saved by _WindowOverflow8().
384 *
385 * FIXME: we really need a fixup handler for this L32E,
386 * for the extremely unlikely case where the overflow handler's
387 * reference thru a0 gets a hardware TLB refill that bumps out
388 * the (distinct, aliasing) TLB entry that mapped its prior
389 * references thru a9, and where our reference now thru a9
390 * gets a 2nd-level miss exception (not hardware TLB refill).
391 */
324 392
325 rsr a3, exccause 393 l32e a2, a9, -16
326 beqi a3, EXCCAUSE_ITLB_MISS, 1f 394 wsr a2, depc # replace the saved a0
327 addi a3, a3, -EXCCAUSE_DTLB_MISS 395 j 1f
328 bnez a3, .Lunrecoverable
3291: movi a3, fast_second_level_miss_double_kernel
330 jx a3
331#else
332.equ .Lksp, .Lunrecoverable
333#endif
334 396
335 /* Critical! We can't handle this situation. PANIC! */ 3972:
398 /*
399 * Restore a0 as saved by _WindowOverflow12().
400 *
401 * FIXME: we really need a fixup handler for this L32E,
402 * for the extremely unlikely case where the overflow handler's
403 * reference thru a0 gets a hardware TLB refill that bumps out
404 * the (distinct, aliasing) TLB entry that mapped its prior
405 * references thru a13, and where our reference now thru a13
406 * gets a 2nd-level miss exception (not hardware TLB refill).
407 */
336 408
337 .extern unrecoverable_exception 409 l32e a2, a13, -16
410 wsr a2, depc # replace the saved a0
4111:
412 /*
413 * Restore WindowBase while leaving all address registers restored.
414 * We have to use ROTW for this, because WSR.WINDOWBASE requires
415 * an address register (which would prevent restore).
416 *
417 * Window Base goes from 0 ... 7 (Module 8)
418 * Window Start is 8 bits; Ex: (0b1010 1010):0x55 from series of call4s
419 */
420
421 rsr a0, ps
422 extui a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
423 rsr a2, windowbase
424 sub a0, a2, a0
425 extui a0, a0, 0, 3
338 426
339.Lunrecoverable_fixup:
340 l32i a2, a3, EXC_TABLE_DOUBLE_SAVE 427 l32i a2, a3, EXC_TABLE_DOUBLE_SAVE
341 xsr a0, depc 428 xsr a3, excsave1
429 beqi a0, 1, .L1pane
430 beqi a0, 3, .L3pane
342 431
343.Lunrecoverable: 432 rsr a0, depc
344 rsr a3, excsave1 433 rotw -2
345 wsr a0, excsave1 434
346 movi a0, unrecoverable_exception 435 /*
347 callx0 a0 436 * We are now in the user code's original window frame.
437 * Process the exception as a user exception as if it was
438 * taken by the user code.
439 *
440 * This is similar to the user exception vector,
441 * except that PT_DEPC isn't set to EXCCAUSE.
442 */
4431:
444 xsr a3, excsave1
445 wsr a2, depc
446 l32i a2, a3, EXC_TABLE_KSTK
447 s32i a0, a2, PT_AREG0
448 rsr a0, exccause
449
450 s32i a0, a2, PT_DEPC
451
452 addx4 a0, a0, a3
453 l32i a0, a0, EXC_TABLE_FAST_USER
454 xsr a3, excsave1
455 jx a0
456
457.L1pane:
458 rsr a0, depc
459 rotw -1
460 j 1b
461
462.L3pane:
463 rsr a0, depc
464 rotw -3
465 j 1b
348 466
349 .end literal_prefix 467 .end literal_prefix
350 468