1/**************************************************************************/ 2/* Copyright (c) Cadence Design Systems, Inc. */ 3/* */ 4/* Permission is hereby granted, free of charge, to any person obtaining */ 5/* a copy of this software and associated documentation files (the */ 6/* "Software"), to deal in the Software without restriction, including */ 7/* without limitation the rights to use, copy, modify, merge, publish, */ 8/* distribute, sublicense, and/or sell copies of the Software, and to */ 9/* permit persons to whom the Software is furnished to do so, subject to */ 10/* the following conditions: */ 11/* */ 12/* The above copyright notice and this permission notice shall be */ 13/* included in all copies or substantial portions of the Software. */ 14/* */ 15/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 16/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 17/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ 18/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ 19/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ 20/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ 21/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 22/**************************************************************************/ 23 24/**************************************************************************/ 25/* */ 26/* DESCRIPTION */ 27/* */ 28/* Xtensa exception and interrupt dispatch for XEA3. */ 29/* */ 30/* Interrupt handlers and user exception handlers support interaction */ 31/* with the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT */ 32/* before and after calling the user's specific interrupt handlers. */ 33/* */ 34/* Users can install application-specific interrupt handlers by calling */ 35/* xt_set_interrupt_handler(). These handlers can be written in C and */ 36/* must follow the C calling convention. The handler table is indexed by */ 37/* the interrupt number. Each handler may be provided with an argument. */ 38/* */ 39/* Users can install application-specific exception handlers in the */ 40/* same way, by calling xt_set_exception_handler(). One handler slot is */ 41/* provided for each exception type. Note that some exceptions are */ 42/* handled by the porting layer itself, and cannot be taken over by */ 43/* application code. These are the alloca, syscall, and coprocessor */ 44/* exceptions. */ 45/* */ 46/* Exception handlers can be written in C, and must follow C calling */ 47/* convention. Each handler is passed a pointer to an exception frame as */ 48/* its single argument. The exception frame is created on the stack and */ 49/* holds the saved context of the thread that took the exception. If the */ 50/* handler returns, the context will be restored and the instruction */ 51/* that caused the exception will be retried. If the handler makes any */ 52/* changes to the saved state in the exception frame, the changes will */ 53/* be applied when restoring the context. */ 54/* */ 55/* RELEASE HISTORY */ 56/* */ 57/* DATE NAME DESCRIPTION */ 58/* */ 59/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ 60/* */ 61/**************************************************************************/ 62 63 64#include <xtensa/config/core.h> 65#include <xtensa/coreasm.h> 66 67#if XCHAL_HAVE_XEA3 68 69#include "xtensa_context.h" 70 71#if (XCHAL_HW_VERSION < XTENSA_HWVERSION_RH_2016_2) 72#error Xtensa HW earlier than RH_2016.2 not supported. 73#endif 74 75 76//----------------------------------------------------------------------------- 77// The entry point vectors are common for call0 and windowed configurations. 78//----------------------------------------------------------------------------- 79 80 .section .DispatchVector.text, "ax" 81#if XCHAL_HAVE_VECBASE 82 .align 64 // 64-byte alignment needed when vecbase 83#else // is relocatable 84 .align 4 85#endif 86 87 .org 0 // Fixed offset for Reset Vector 88 .global _DispatchVector 89 .weak _DispatchVector 90 91_DispatchVector: 92 j _JumpToResetHandler 93 94 .org 3 // Reserved 95 .local _Reserved1 96 97_Reserved1: 98 ill 99 100 .org 6 // Fixed offset for Double Exception Vector 101 .global _DoubleExceptionVector 102 .weak _DoubleExceptionVector 103 104_DoubleExceptionVector: 105 j _DoubleExceptionHandler // Externally defined 106 107 .org 9 // Reserved 108 .local _Reserved2 109 110_Reserved2: 111 ill 112 113//----------------------------------------------------------------------------- 114// Start of dispatch code. 115//----------------------------------------------------------------------------- 116 117 .org 12 // Fixed offset for Tailchain entry point 118 .global _xt_dispatch 119 120_xt_dispatch: 121#ifdef __XTENSA_CALL0_ABI__ 122 123 // NOTE: for call0, a15 is expected to be holding the previous stack pointer 124 // when we get to the Tailchain segment. 125 126 s32si.x4 a2, a15 // Select interrupt, a2 <- (intnum << 2) 127 movi a0, 0 128 l32dis.it a0, a0 // a0 <- wrapper addr (handler_table[0]) 129 s32stk a9, a15, 96 // Set new stack pointer 130#if XT_STK_XTRA_SZ 131 addi a1, a1, -XT_STK_XTRA_SZ // Adjust for extra save area 132#endif 133 s32dis.h a0, a0 // Jump to handler if interrupt else fall through 134 // Note this also clears local exclusive monitor 135 136#else // windowed 137 138 s32si.x4 a10, a1 // Select interrupt, a10 <- (intnum << 2) 139 movi a8, 0 140 l32dis.it a8, a8 // a8 <- wrapper addr (handler_table[0]) 141 s32stk a9, a1, 96 // Set new stack pointer 142#if XT_STK_XTRA_SZ 143 addi a9, a9, -XT_STK_XTRA_SZ // Adjust for extra save area 144#endif 145 s32dis.h a8, a8 // Jump to handler if interrupt else fall through 146 // Note this also clears local exclusive monitor 147 148#endif // __XTENSA_CALL0_ABI__ 149 150.Lexit: 151 j _xt_exit 152 153#ifndef __XTENSA_CALL0_ABI__ 154 .org 36 // Fixed offset for Underflow segment 155 .global _xt_underflow 156 157_xt_underflow: 158 l32e a8, a1, -64 // a8 <- [a1-32] 159 l32e a9, a1, -64 // a9 <- [a1-28] 160 l32e a10, a1, -64 // a10 <- [a1-24] 161 l32e a11, a1, -64 // a11 <- [a1-20] 162 l32e a12, a1, -64 // a12 <- [a1-16] 163 l32e a13, a1, -64 // a13 <- [a1-12] 164 l32e a14, a1, -64 // a14 <- [a1-8] 165 l32e a15, a1, -64 // a15 <- [a1-4] ; Return (branch to EPC) 166#endif 167 168 .org 60 // Fixed offset for Save/Overflow segment 169 .global _xt_save 170 171_xt_save: 172#ifdef __XTENSA_CALL0_ABI__ 173 s32e a0, a1, -64 // [a1-64] <- a0 174 s32e a2, a1, -48 // [a1-56] <- a2 ; a2 <- EPC 175 s32e a3, a1, -64 // [a1-52] <- a3 176 s32e a4, a1, -64 // [a1-48] <- a4 177 s32e a5, a1, -64 // [a1-44] <- a5 178 s32e a6, a1, -64 // [a1-40] <- a6 179 s32e a7, a1, -64 // [a1-36] <- a7 180#else 181 .global _xt_overflow 182_xt_overflow: 183#endif 184 s32e a8, a1, -52 // [a1-32] <- a8 ; a8 <- ExcVAddr 185 s32e a9, a1, -28 // [a1-28] <- a9 ; a9 <- PS/SAR 186 s32e a10, a1, -48 // [a1-24] <- a10 ; a10 <- EPC 187 s32e a11, a1, -24 // [a1-20] <- a11 ; a11 <- ExcCause 188 s32e a12, a1, -44 // [a1-16] <- a12 ; a12 <- LBEG 189 s32e a13, a1, -40 // [a1-12] <- a13 ; a13 <- LEND 190 s32e a14, a1, -36 // [a1-8] <- a14 ; a14 <- LCOUNT 191 s32e a15, a1, -32 // [a1-4] <- a15 ; a15 <- a1 192 // If Overflow then return (branch to EPC) 193 194_xt_entry: 195 s32e a8, a1, -4 // [a1-68] <- a8 (ExcVAddr) 196 s32e a11, a1, -8 // [a1-72] <- a11 (ExcCause) 197#if XCHAL_HAVE_LOOPS 198 s32e a12, a1, -20 // [a1-84] <- a12 (LBEG) 199 s32e a13, a1, -24 // [a1-88] <- a13 (LEND) 200 s32e a14, a1, -28 // [a1-92] <- a14 (LCOUNT) 201#endif 202#if XCHAL_HAVE_EXCLUSIVE 203 movi a12, 0 204 getex a12 205 s32e a12, a1, -32 // [a1-96] <- a12 (ATOMCTL) 206#endif 207 208 j 1f // make room for literals 209 210 .align 4 211 .literal_position 212 213.Le1: 214 .word _xt_exception_table 215 2161: 217 // Call OS-specific code for additional work to be done. Stay on interruptee's 218 // stack in case more saves are required into stack frame. 219 // NOTE: OS-specific code can use a8, a12-a14, (+a2-a7: call0, a15: windowed). 220 // ALL other registers must be preserved. 221 222 XT_RTOS_INT_ENTER 223 224 // This sequence checks the interrupt controller and loads the interrupt 225 // number if available, and also loads the wrapper handler address. 226 // If there is an interrupt, execution will branch to the wrapper which 227 // will then forward to the correct handler. 228 // All this happens only if there is a pending interrupt. If not, execution 229 // falls through to exception handling. 230 231#ifdef __XTENSA_CALL0_ABI__ 232 233 s32si.x4 a2, a1 // [a1-80] <- a2 (EPC) ; a2 <- (intnum << 2) 234 movi a0, 0 235 l32dis.it a0, a0 // a0 <- wrapper addr (handler_table[0]) 236 s32stk a9, a1, 96 // [a1-76] <- a9 (PS/SAR) ; a1 = a1-96 237#if XT_STK_XTRA_SZ 238 addi a1, a1, -XT_STK_XTRA_SZ // Adjust for extra save area 239#endif 240 s32dis.h a0, a0 // Jump to handler if interrupt else fall through 241 242#else // windowed 243 244 s32si.x4 a10, a1 // [a1-80] <- a10 (EPC) ; a10 <- (intnum << 2) 245 movi a8, 0 246 l32dis.it a8, a8 // a8 <- wrapper addr (handler_table[0]) 247 s32stk a9, a1, 96 // [a1-76] <- a9 (PS/SAR) ; a9 = a1-96 248#if XT_STK_XTRA_SZ 249 addi a9, a9, -XT_STK_XTRA_SZ // Adjust for extra save area 250#endif 251 s32dis.h a8, a8 // Jump to handler if interrupt else fall through 252 253#endif // __XTENSA_CALL0_ABI__ 254 255 // At this point we have: 256 // (note window has rotated for windowed ABI) 257 // a0 holds return address (Tailchain+3) 258 // For call0: 259 // a11 holds ExcCause, also saved in [oldsp - 72] 260 // a15 holds exception SP, a1 points to exception frame 261 // For windowed: 262 // a3 holds ExcCause, also saved in [oldsp - 72] 263 // a1 points to exception frame 264 265 .global _xt_exception 266 267_xt_exception: 268 l32r a2, .Le1 // Load exc table address 269#ifdef __XTENSA_CALL0_ABI__ 270 mov a3, a11 // Copy exception cause to a3 271#endif 272 extui a4, a3, 0, 4 // Extract exception cause 273 addx4 a2, a4, a2 // Index into exc table 274 l32i a4, a2, 0 // Load handler address 275#if XT_STK_XTRA_SZ 276 addi a2, a1, XT_STK_XTRA_SZ // Argument = Exception frame ptr 277#else 278 mov a2, a1 // Argument = Exception frame ptr 279#endif 280 jx a4 // Return directly from handler 281 282 // Exit/restore sequence 283 284 .global _xt_exit 285 286_xt_exit: 287#ifdef __XTENSA_CALL0_ABI__ 288 mov a1, a15 // Restore stack pointer 289#endif 290 291 // Run OS-specific code to determine what to restore. 292 // Interrupts will remain disabled through this sequence. 293 // WARNING: stack pointer may change within this macro 294 // so all restores off the stack must happen afterwards. 295 296 XT_RTOS_INT_EXIT 297 298 .global _xt_restore 299 300_xt_restore: 301 // Some loads must happen before DISPST = Restore, as these 302 // will not be accessible via L32E once DISPST = Restore. 303 304#if XCHAL_HAVE_EXCLUSIVE 305 l32e a12, a1, -32 // a12 <- [a1-96] (ATOMCTL) 306 getex a12 307#endif 308 l32e a10, a1, -12 // a10 <- [a1-76] (PS/SAR) 309 l32e a12, a1, -20 // a12 <- [a1-84] (LBEG) 310 l32e a13, a1, -24 // a13 <- [a1-88] (LEND) 311 l32e a14, a1, -28 // a14 <- [a1-92] (LCOUNT) 312 l32dis.epc a11, a1 // a11 <- [a1-80] (EPC) 313 // If interrupt goto tailchain else fall through 314 315#ifdef __XTENSA_CALL0_ABI__ 316 l32e a0, a1, -64 // a0 <- [a1-64] 317 l32e a2, a1, -64 // a2 <- [a1-56] 318 l32e a3, a1, -64 // a3 <- [a1-52] 319 l32e a4, a1, -64 // a4 <- [a1-48] 320 l32e a5, a1, -64 // a5 <- [a1-44] 321 l32e a6, a1, -64 // a6 <- [a1-40] 322 l32e a7, a1, -64 // a7 <- [a1-36] 323#endif 324 325 // Important: the following restrictions must be observed: 326 // 1) The LCOUNT register must be restored after LBEG/LEND. 327 // 2) There must be at least 3 instructions between the LCOUNT 328 // restore and the last L32E (the one that branches). 329 330 l32e a12, a1, -44 // LBEG <- a12, a12 <- [a1-16] 331 l32e a13, a1, -40 // LEND <- a13, a13 <- [a1-12] 332 l32e a14, a1, -36 // LCOUNT <- a14, a14 <- [a1-8] 333 l32e a8, a1, -64 // a8 <- [a1-32] 334 l32e a9, a1, -64 // a9 <- [a1-28] 335 l32e a10, a1, -60 // PS/SAR <- a10, a10 <- [a1-24] 336 l32e a11, a1, -48 // EPC <- a11, a11 <- [a1-20] 337 l32e a15, a1, -64 // a15 <- [a1-4], Branch to EPC if no interrupt 338 // If interrupt, branch to Tailchain 339 340 341//----------------------------------------------------------------------------- 342// Branch to reset handler code from here. Use CALL0 as a branch, will expand 343// to CALLX0 if needed when built with the -mlongcalls option. 344//----------------------------------------------------------------------------- 345 346 .align 4 347 .local _JumpToResetHandler 348 349_JumpToResetHandler: 350 call0 _ResetHandler 351 352 353//----------------------------------------------------------------------------- 354// Idle loop. On interrupt, no state needs saving. 355//----------------------------------------------------------------------------- 356 357 .align 4 358 .global _xt_idle 359 360_xt_idle: 361 movi a14, _xt_interrupt_stack_top 362 mov a1, a14 // a1 <- Top of interrupt stack 363 movi a14, 0 // 0 = Normal 364 wsr.ms a14 // Set DISPST = Normal 365 rsync 366 waiti 0 // Wait for interrupt 367 memw // HW erratum 569 368 369 370//----------------------------------------------------------------------------- 371// Scheduler interrupt handler. Triggered by context switch. At this time only 372// useful for windowed ABI to spill register windows. 373//----------------------------------------------------------------------------- 374 375 .align 4 376 .global xt_sched_handler 377 378xt_sched_handler: 379#ifdef __XTENSA_WINDOWED_ABI__ 380 entry a1, 32 381 ssai 1 382 spillw 383 retw 384#else 385 ret 386#endif 387 388#endif // XCHAL_HAVE_XEA3 389 390