Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | /* * Copyright (c) 2016 Cadence Design Systems, Inc. * SPDX-License-Identifier: Apache-2.0 */ #include "xtensa_rtos.h" /* WINDOW OVERFLOW AND UNDERFLOW EXCEPTION VECTORS AND ALLOCA EXCEPTION * HANDLER * * Here is the code for each window overflow/underflow exception vector and * (interspersed) efficient code for handling the alloca exception cause. * Window exceptions are handled entirely in the vector area and are very tight * for performance. The alloca exception is also handled entirely in the window * vector area so comes at essentially no cost in code size. Users should never * need to modify them and Cadence Design Systems recommends they do not. * * Window handlers go at predetermined vector locations according to the Xtensa * hardware configuration, which is ensured by their placement in a special * section known to the Xtensa linker support package (LSP). Since their * offsets in that section are always the same, the LSPs do not define a * section per vector. * * These things are coded for XEA2 only (XEA1 is not supported). * * Note on Underflow Handlers: * * The underflow handler for returning from call[i+1] to call[i] must preserve * all the registers from call[i+1]'s window. In particular, a0 and a1 must be * preserved because the RETW instruction will be reexecuted (and may even * underflow if an intervening exception has flushed call[i]'s registers). * Registers a2 and up may contain return values. */ #if XCHAL_HAVE_WINDOWED .section .WindowVectors.text, "ax" /* Window Overflow Exception for Call4. * * Invoked if a call[i] referenced a register (a4-a15) * that contains data from ancestor call[j]; * call[j] had done a call4 to call[j+1]. * On entry here: * window rotated to call[j] start point; * a0-a3 are registers to be saved; * a4-a15 must be preserved; * a5 is call[j+1]'s stack pointer. */ .org 0x0 .global _WindowOverflow4 _WindowOverflow4: s32e a0, a5, -16 /* save a0 to call[j+1]'s stack frame */ s32e a1, a5, -12 /* save a1 to call[j+1]'s stack frame */ s32e a2, a5, -8 /* save a2 to call[j+1]'s stack frame */ s32e a3, a5, -4 /* save a3 to call[j+1]'s stack frame */ rfwo /* rotates back to call[i] position */ /* Window Underflow Exception for Call4 * * Invoked by RETW returning from call[i+1] to call[i] * where call[i]'s registers must be reloaded (not live in ARs); * where call[i] had done a call4 to call[i+1]. * On entry here: * window rotated to call[i] start point; * a0-a3 are undefined, must be reloaded with call[i].reg[0..3]; * a4-a15 must be preserved (they are call[i+1].reg[0..11]); * a5 is call[i+1]'s stack pointer. */ .org 0x40 .global _WindowUnderflow4 _WindowUnderflow4: l32e a0, a5, -16 /* restore a0 from call[i+1]'s stack frame */ l32e a1, a5, -12 /* restore a1 from call[i+1]'s stack frame */ l32e a2, a5, -8 /* restore a2 from call[i+1]'s stack frame */ l32e a3, a5, -4 /* restore a3 from call[i+1]'s stack frame */ rfwu /* Handle alloca exception generated by interruptee executing 'movsp'. * This uses space between the window vectors, so is essentially "free". * All interruptee's regs are intact except a0 which is saved in EXCSAVE_1, * and PS.EXCM has been set by the exception hardware (can't be interrupted). * The fact the alloca exception was taken means the registers associated with * the base-save area have been spilled and will be restored by the underflow * handler, so those 4 registers are available for scratch. * The code is optimized to avoid unaligned branches and minimize cache misses. */ .align 4 .global _xt_alloca_exc _xt_alloca_exc: rsr a0, WINDOWBASE /* grab WINDOWBASE before rotw changes it */ rotw -1 /* WINDOWBASE goes to a4, new a0-a3 are scratch */ rsr a2, PS extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS xor a3, a3, a4 /* bits changed from old to current windowbase */ rsr a4, EXCSAVE_1 /* restore original a0 (now in a4) */ slli a3, a3, XCHAL_PS_OWB_SHIFT xor a2, a2, a3 /* flip changed bits in old window base */ wsr a2, PS /* update PS.OWB to new window base */ rsync _bbci.l a4, 31, _WindowUnderflow4 rotw -1 /* original a0 goes to a8 */ _bbci.l a8, 30, _WindowUnderflow8 rotw -1 j _WindowUnderflow12 /* Window Overflow Exception for Call8 * * Invoked if a call[i] referenced a register (a4-a15) * that contains data from ancestor call[j]; * call[j] had done a call8 to call[j+1]. * On entry here: * window rotated to call[j] start point; * a0-a7 are registers to be saved; * a8-a15 must be preserved; * a9 is call[j+1]'s stack pointer. */ .org 0x80 .global _WindowOverflow8 _WindowOverflow8: s32e a0, a9, -16 /* save a0 to call[j+1]'s stack frame */ l32e a0, a1, -12 /* a0 <- call[j-1]'s sp (used to find end of call[j]'s frame) */ s32e a1, a9, -12 /* save a1 to call[j+1]'s stack frame */ s32e a2, a9, -8 /* save a2 to call[j+1]'s stack frame */ s32e a3, a9, -4 /* save a3 to call[j+1]'s stack frame */ s32e a4, a0, -32 /* save a4 to call[j]'s stack frame */ s32e a5, a0, -28 /* save a5 to call[j]'s stack frame */ s32e a6, a0, -24 /* save a6 to call[j]'s stack frame */ s32e a7, a0, -20 /* save a7 to call[j]'s stack frame */ rfwo /* rotates back to call[i] position */ /* * Window Underflow Exception for Call8 * * Invoked by RETW returning from call[i+1] to call[i] * where call[i]'s registers must be reloaded (not live in ARs); * where call[i] had done a call8 to call[i+1]. * On entry here: * window rotated to call[i] start point; * a0-a7 are undefined, must be reloaded with call[i].reg[0..7]; * a8-a15 must be preserved (they are call[i+1].reg[0..7]); * a9 is call[i+1]'s stack pointer. */ .org 0xC0 .global _WindowUnderflow8 _WindowUnderflow8: l32e a0, a9, -16 /* restore a0 from call[i+1]'s stack frame */ l32e a1, a9, -12 /* restore a1 from call[i+1]'s stack frame */ l32e a2, a9, -8 /* restore a2 from call[i+1]'s stack frame */ l32e a7, a1, -12 /* a7 <- call[i-1]'s sp (used to find end of call[i]'s frame) */ l32e a3, a9, -4 /* restore a3 from call[i+1]'s stack frame */ l32e a4, a7, -32 /* restore a4 from call[i]'s stack frame */ l32e a5, a7, -28 /* restore a5 from call[i]'s stack frame */ l32e a6, a7, -24 /* restore a6 from call[i]'s stack frame */ l32e a7, a7, -20 /* restore a7 from call[i]'s stack frame */ rfwu /* * Window Overflow Exception for Call12 * * Invoked if a call[i] referenced a register (a4-a15) * that contains data from ancestor call[j]; * call[j] had done a call12 to call[j+1]. * On entry here: * window rotated to call[j] start point; * a0-a11 are registers to be saved; * a12-a15 must be preserved; * a13 is call[j+1]'s stack pointer. */ .org 0x100 .global _WindowOverflow12 _WindowOverflow12: s32e a0, a13, -16 /* save a0 to call[j+1]'s stack frame */ l32e a0, a1, -12 /* a0 <- call[j-1]'s sp (used to find end of call[j]'s frame) */ s32e a1, a13, -12 /* save a1 to call[j+1]'s stack frame */ s32e a2, a13, -8 /* save a2 to call[j+1]'s stack frame */ s32e a3, a13, -4 /* save a3 to call[j+1]'s stack frame */ s32e a4, a0, -48 /* save a4 to end of call[j]'s stack frame */ s32e a5, a0, -44 /* save a5 to end of call[j]'s stack frame */ s32e a6, a0, -40 /* save a6 to end of call[j]'s stack frame */ s32e a7, a0, -36 /* save a7 to end of call[j]'s stack frame */ s32e a8, a0, -32 /* save a8 to end of call[j]'s stack frame */ s32e a9, a0, -28 /* save a9 to end of call[j]'s stack frame */ s32e a10, a0, -24 /* save a10 to end of call[j]'s stack frame */ s32e a11, a0, -20 /* save a11 to end of call[j]'s stack frame */ rfwo /* rotates back to call[i] position */ /* * Window Underflow Exception for Call12 * * Invoked by RETW returning from call[i+1] to call[i] * where call[i]'s registers must be reloaded (not live in ARs); * where call[i] had done a call12 to call[i+1]. * On entry here: * window rotated to call[i] start point; * a0-a11 are undefined, must be reloaded with call[i].reg[0..11]; * a12-a15 must be preserved (they are call[i+1].reg[0..3]); * a13 is call[i+1]'s stack pointer. */ .org 0x140 .global _WindowUnderflow12 _WindowUnderflow12: l32e a0, a13, -16 /* restore a0 from call[i+1]'s stack frame */ l32e a1, a13, -12 /* restore a1 from call[i+1]'s stack frame */ l32e a2, a13, -8 /* restore a2 from call[i+1]'s stack frame */ l32e a11, a1, -12 /* a11 <- call[i-1]'s sp * (used to find end of call[i]'s frame) */ l32e a3, a13, -4 /* restore a3 from call[i+1]'s stack frame */ l32e a4, a11, -48 /* restore a4 from end of call[i]'s stack frame */ l32e a5, a11, -44 /* restore a5 from end of call[i]'s stack frame */ l32e a6, a11, -40 /* restore a6 from end of call[i]'s stack frame */ l32e a7, a11, -36 /* restore a7 from end of call[i]'s stack frame */ l32e a8, a11, -32 /* restore a8 from end of call[i]'s stack frame */ l32e a9, a11, -28 /* restore a9 from end of call[i]'s stack frame */ l32e a10, a11, -24 /* restore a10 from end of call[i]'s stack * frame */ l32e a11, a11, -20 /* restore a11 from end of call[i]'s stack * frame */ rfwu #endif /* XCHAL_HAVE_WINDOWED */ |