diff options
Diffstat (limited to 'arch/xtensa')
-rw-r--r-- | arch/xtensa/include/asm/regs.h | 1 | ||||
-rw-r--r-- | arch/xtensa/kernel/align.S | 5 | ||||
-rw-r--r-- | arch/xtensa/kernel/coprocessor.S | 9 | ||||
-rw-r--r-- | arch/xtensa/kernel/entry.S | 115 | ||||
-rw-r--r-- | arch/xtensa/kernel/vectors.S | 250 |
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 | ||
110 | ENTRY(user_exception) | 110 | ENTRY(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 | ||
256 | ENTRY(kernel_exception) | 255 | ENTRY(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 | ||
1015 | ENTRY(fast_syscall_kernel) | 1011 | ENTRY(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 | ||
1115 | ENTRY(fast_syscall_xtensa) | 1110 | ENTRY(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 | ||
1571 | ENTRY(fast_second_level_miss) | 1560 | ENTRY(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 | |||
1600 | 8: rsr a3, excvaddr # fault address | 1587 | 8: 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 | ||
1650 | 4: movi a3, exc_table # restore a3 | 1637 | 4: 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 | ||
1744 | 2: /* Invalid PGD, default exception handling */ | 1731 | 2: /* 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 | ||
1778 | ENTRY(fast_store_prohibited) | 1762 | ENTRY(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 | ||
1789 | 8: rsr a1, excvaddr # fault address | 1773 | 8: 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 | ||
1846 | 2: /* If there was a problem, handle fault in C */ | 1828 | 2: /* 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 | ||
83 | ENDPROC(_UserExceptionVector) | 84 | ENDPROC(_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 | ||
109 | ENDPROC(_KernelExceptionVector) | 111 | ENDPROC(_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 | ||
208 | ENTRY(_DoubleExceptionVector) | 212 | ENTRY(_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 | ||
290 | 1: 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 | ||
329 | 1: 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! */ | 397 | 2: |
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 | ||
411 | 1: | ||
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 | */ | ||
443 | 1: | ||
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 | ||