diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2013-10-14 18:22:42 -0400 |
---|---|---|
committer | Chris Zankel <chris@zankel.net> | 2013-10-15 16:39:06 -0400 |
commit | 244066f4be8ce2dc2d2d60f01bceeba55c71a783 (patch) | |
tree | a1a266f7ae41b3418a1f858712c52ba3cf141100 /arch/xtensa/kernel/entry.S | |
parent | 61e6cfa80de5760bbe406f4e815b7739205754d2 (diff) |
xtensa: fix fast_syscall_spill_registers_fixup
fast_syscall_spill_registers_fixup was not correctly updated by the
'keep a3 and excsave1 on entry to exception handlers' patch: it doesn't
preserve a3 that it gets on entry, breaking _spill_registers in case of
page fault on stack during register spilling, leading to unhandled
exception in kernel mode.
Preserve a3 by saving it in the original _spill_registers stack frame's
a3 during exception handling and restoring it afterwards.
Also fix comments and function bounds annotations.
Reported-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Tested-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Chris Zankel <chris@zankel.net>
Diffstat (limited to 'arch/xtensa/kernel/entry.S')
-rw-r--r-- | arch/xtensa/kernel/entry.S | 49 |
1 files changed, 30 insertions, 19 deletions
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index de1dfa18d0a1..21dbe6bdb8ed 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S | |||
@@ -1122,7 +1122,7 @@ ENDPROC(fast_syscall_spill_registers) | |||
1122 | * a3: exctable, original value in excsave1 | 1122 | * a3: exctable, original value in excsave1 |
1123 | */ | 1123 | */ |
1124 | 1124 | ||
1125 | fast_syscall_spill_registers_fixup: | 1125 | ENTRY(fast_syscall_spill_registers_fixup) |
1126 | 1126 | ||
1127 | rsr a2, windowbase # get current windowbase (a2 is saved) | 1127 | rsr a2, windowbase # get current windowbase (a2 is saved) |
1128 | xsr a0, depc # restore depc and a0 | 1128 | xsr a0, depc # restore depc and a0 |
@@ -1134,22 +1134,26 @@ fast_syscall_spill_registers_fixup: | |||
1134 | */ | 1134 | */ |
1135 | 1135 | ||
1136 | xsr a3, excsave1 # get spill-mask | 1136 | xsr a3, excsave1 # get spill-mask |
1137 | slli a2, a3, 1 # shift left by one | 1137 | slli a3, a3, 1 # shift left by one |
1138 | 1138 | ||
1139 | slli a3, a2, 32-WSBITS | 1139 | slli a2, a3, 32-WSBITS |
1140 | src a2, a2, a3 # a1 = xxwww1yyxxxwww1yy...... | 1140 | src a2, a3, a2 # a2 = xxwww1yyxxxwww1yy...... |
1141 | wsr a2, windowstart # set corrected windowstart | 1141 | wsr a2, windowstart # set corrected windowstart |
1142 | 1142 | ||
1143 | rsr a3, excsave1 | 1143 | srli a3, a3, 1 |
1144 | l32i a2, a3, EXC_TABLE_DOUBLE_SAVE # restore a2 | 1144 | rsr a2, excsave1 |
1145 | l32i a3, a3, EXC_TABLE_PARAM # original WB (in user task) | 1145 | l32i a2, a2, EXC_TABLE_DOUBLE_SAVE # restore a2 |
1146 | xsr a2, excsave1 | ||
1147 | s32i a3, a2, EXC_TABLE_DOUBLE_SAVE # save a3 | ||
1148 | l32i a3, a2, EXC_TABLE_PARAM # original WB (in user task) | ||
1149 | xsr a2, excsave1 | ||
1146 | 1150 | ||
1147 | /* Return to the original (user task) WINDOWBASE. | 1151 | /* Return to the original (user task) WINDOWBASE. |
1148 | * We leave the following frame behind: | 1152 | * We leave the following frame behind: |
1149 | * a0, a1, a2 same | 1153 | * a0, a1, a2 same |
1150 | * a3: trashed (saved in excsave_1) | 1154 | * a3: trashed (saved in EXC_TABLE_DOUBLE_SAVE) |
1151 | * depc: depc (we have to return to that address) | 1155 | * depc: depc (we have to return to that address) |
1152 | * excsave_1: a3 | 1156 | * excsave_1: exctable |
1153 | */ | 1157 | */ |
1154 | 1158 | ||
1155 | wsr a3, windowbase | 1159 | wsr a3, windowbase |
@@ -1159,9 +1163,9 @@ fast_syscall_spill_registers_fixup: | |||
1159 | * a0: return address | 1163 | * a0: return address |
1160 | * a1: used, stack pointer | 1164 | * a1: used, stack pointer |
1161 | * a2: kernel stack pointer | 1165 | * a2: kernel stack pointer |
1162 | * a3: available, saved in EXCSAVE_1 | 1166 | * a3: available |
1163 | * depc: exception address | 1167 | * depc: exception address |
1164 | * excsave: a3 | 1168 | * excsave: exctable |
1165 | * Note: This frame might be the same as above. | 1169 | * Note: This frame might be the same as above. |
1166 | */ | 1170 | */ |
1167 | 1171 | ||
@@ -1181,9 +1185,12 @@ fast_syscall_spill_registers_fixup: | |||
1181 | rsr a0, exccause | 1185 | rsr a0, exccause |
1182 | addx4 a0, a0, a3 # find entry in table | 1186 | addx4 a0, a0, a3 # find entry in table |
1183 | l32i a0, a0, EXC_TABLE_FAST_USER # load handler | 1187 | l32i a0, a0, EXC_TABLE_FAST_USER # load handler |
1188 | l32i a3, a3, EXC_TABLE_DOUBLE_SAVE | ||
1184 | jx a0 | 1189 | jx a0 |
1185 | 1190 | ||
1186 | fast_syscall_spill_registers_fixup_return: | 1191 | ENDPROC(fast_syscall_spill_registers_fixup) |
1192 | |||
1193 | ENTRY(fast_syscall_spill_registers_fixup_return) | ||
1187 | 1194 | ||
1188 | /* When we return here, all registers have been restored (a2: DEPC) */ | 1195 | /* When we return here, all registers have been restored (a2: DEPC) */ |
1189 | 1196 | ||
@@ -1191,13 +1198,13 @@ fast_syscall_spill_registers_fixup_return: | |||
1191 | 1198 | ||
1192 | /* Restore fixup handler. */ | 1199 | /* Restore fixup handler. */ |
1193 | 1200 | ||
1194 | xsr a3, excsave1 | 1201 | rsr a2, excsave1 |
1195 | movi a2, fast_syscall_spill_registers_fixup | 1202 | s32i a3, a2, EXC_TABLE_DOUBLE_SAVE |
1196 | s32i a2, a3, EXC_TABLE_FIXUP | 1203 | movi a3, fast_syscall_spill_registers_fixup |
1197 | s32i a0, a3, EXC_TABLE_DOUBLE_SAVE | 1204 | s32i a3, a2, EXC_TABLE_FIXUP |
1198 | rsr a2, windowbase | 1205 | rsr a3, windowbase |
1199 | s32i a2, a3, EXC_TABLE_PARAM | 1206 | s32i a3, a2, EXC_TABLE_PARAM |
1200 | l32i a2, a3, EXC_TABLE_KSTK | 1207 | l32i a2, a2, EXC_TABLE_KSTK |
1201 | 1208 | ||
1202 | /* Load WB at the time the exception occurred. */ | 1209 | /* Load WB at the time the exception occurred. */ |
1203 | 1210 | ||
@@ -1206,8 +1213,12 @@ fast_syscall_spill_registers_fixup_return: | |||
1206 | wsr a3, windowbase | 1213 | wsr a3, windowbase |
1207 | rsync | 1214 | rsync |
1208 | 1215 | ||
1216 | rsr a3, excsave1 | ||
1217 | l32i a3, a3, EXC_TABLE_DOUBLE_SAVE | ||
1218 | |||
1209 | rfde | 1219 | rfde |
1210 | 1220 | ||
1221 | ENDPROC(fast_syscall_spill_registers_fixup_return) | ||
1211 | 1222 | ||
1212 | /* | 1223 | /* |
1213 | * spill all registers. | 1224 | * spill all registers. |