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