diff options
| -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 | ||
