Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Max Filippov and committed by
Chris Zankel
99d5040e 16c5becf

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