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/* */ 27/* DESCRIPTION */ 28/* */ 29/* XTENSA CONTEXT SAVE AND RESTORE ROUTINES */ 30/* */ 31/* Low-level functions for handling generic context save and restore of */ 32/* registers not specifically addressed by the interrupt vectors and */ 33/* handlers. Those registers (not handled by these functions) are PC, PS, */ 34/* A0, A1 (SP). Except for the calls to RTOS functions, this code is */ 35/* generic to Xtensa. */ 36/* */ 37/* Note that in Call0 ABI, interrupt handlers are expected to preserve */ 38/* the callee-save regs (A12-A15), which is always the case if the */ 39/* handlers are coded in C. However A12, A13 are made available as */ 40/* scratch registers for interrupt dispatch code, so are presumed saved */ 41/* anyway, and are always restored even in Call0 ABI. Only A14, A15 are */ 42/* truly handled as callee-save regs. */ 43/* */ 44/* RELEASE HISTORY */ 45/* */ 46/* DATE NAME DESCRIPTION */ 47/* */ 48/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ 49/* */ 50/**************************************************************************/ 51 52 53#include "xtensa_rtos.h" 54 55#ifdef XT_USE_OVLY 56#include <xtensa/overlay_os_asm.h> 57#endif 58 59 .text 60 61#if XCHAL_HAVE_XEA2 62 63/*************************************************************************** 64 65 _xt_context_save 66 67 !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !! 68 69Saves all Xtensa processor state except PC, PS, A0, A1 (SP), A12, A13, in the 70interrupt stack frame defined in xtensa_rtos.h. 71Its counterpart is _xt_context_restore (which also restores A12, A13). 72 73Caller is expected to have saved PC, PS, A0, A1 (SP), A12, A13 in the frame. 74This function preserves A12 & A13 in order to provide the caller with 2 scratch 75regs that need not be saved over the call to this function. The choice of which 762 regs to provide is governed by xthal_window_spill_nw and xthal_save_extra_nw, 77to avoid moving data more than necessary. Caller can assign regs accordingly. 78 79Entry Conditions: 80 A0 = Return address in caller. 81 A1 = Stack pointer of interrupted thread or handler ("interruptee"). 82 Original A12, A13 have already been saved in the interrupt stack frame. 83 Other processor state except PC, PS, A0, A1 (SP), A12, A13, is as at the 84 point of interruption. 85 If windowed ABI, PS.EXCM = 1 (exceptions disabled). 86 87Exit conditions: 88 A0 = Return address in caller. 89 A1 = Stack pointer of interrupted thread or handler ("interruptee"). 90 A12, A13 as at entry (preserved). 91 If windowed ABI, PS.EXCM = 1 (exceptions disabled). 92 93***************************************************************************/ 94 95 .global _xt_context_save 96 .type _xt_context_save,@function 97 .align 4 98_xt_context_save: 99 100 s32i a2, sp, XT_STK_A2 101 s32i a3, sp, XT_STK_A3 102 s32i a4, sp, XT_STK_A4 103 s32i a5, sp, XT_STK_A5 104 s32i a6, sp, XT_STK_A6 105 s32i a7, sp, XT_STK_A7 106 s32i a8, sp, XT_STK_A8 107 s32i a9, sp, XT_STK_A9 108 s32i a10, sp, XT_STK_A10 109 s32i a11, sp, XT_STK_A11 110 111 /* 112 Call0 ABI callee-saved regs a12-15 do not need to be saved here. 113 a12-13 are the caller's responsibility so it can use them as scratch. 114 So only need to save a14-a15 here for Windowed ABI (not Call0). 115 */ 116 #ifndef __XTENSA_CALL0_ABI__ 117 s32i a14, sp, XT_STK_A14 118 s32i a15, sp, XT_STK_A15 119 #endif 120 121 rsr a3, SAR 122 s32i a3, sp, XT_STK_SAR 123 124 #if XCHAL_HAVE_LOOPS 125 rsr a3, LBEG 126 s32i a3, sp, XT_STK_LBEG 127 rsr a3, LEND 128 s32i a3, sp, XT_STK_LEND 129 rsr a3, LCOUNT 130 s32i a3, sp, XT_STK_LCOUNT 131 #endif 132 133 #if XCHAL_HAVE_EXCLUSIVE 134 /* Save and clear state of ATOMCTL */ 135 movi a3, 0 136 getex a3 137 s32i a3, sp, XT_STK_ATOMCTL 138 #endif 139 140 #if XT_USE_SWPRI 141 /* Save virtual priority mask */ 142 movi a3, _xt_vpri_mask 143 l32i a3, a3, 0 144 s32i a3, sp, XT_STK_VPRI 145 #endif 146 147 #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__) 148 mov a9, a0 /* preserve ret addr */ 149 #endif 150 151 #ifndef __XTENSA_CALL0_ABI__ 152 /* 153 To spill the reg windows, temp. need pre-interrupt stack ptr and a4-15. 154 Need to save a9,12,13 temporarily (in frame temps) and recover originals. 155 Interrupts need to be disabled below XCHAL_EXCM_LEVEL and window overflow 156 and underflow exceptions disabled (assured by PS.EXCM == 1). 157 */ 158 s32i a12, sp, XT_STK_TMP0 /* temp. save stuff in stack frame */ 159 s32i a13, sp, XT_STK_TMP1 160 s32i a9, sp, XT_STK_TMP2 161 162 /* 163 Save the overlay state if we are supporting overlays. Since we just saved 164 three registers, we can conveniently use them here. Note that as of now, 165 overlays only work for windowed calling ABI. 166 */ 167 #ifdef XT_USE_OVLY 168 l32i a9, sp, XT_STK_PC /* recover saved PC */ 169 _xt_overlay_get_state a9, a12, a13 170 s32i a9, sp, XT_STK_OVLY /* save overlay state */ 171 #endif 172 173 l32i a12, sp, XT_STK_A12 /* recover original a9,12,13 */ 174 l32i a13, sp, XT_STK_A13 175 l32i a9, sp, XT_STK_A9 176 addi sp, sp, XT_STK_FRMSZ /* restore the interruptee's SP */ 177 call0 xthal_window_spill_nw /* preserves only a4,5,8,9,12,13 */ 178 addi sp, sp, -XT_STK_FRMSZ 179 l32i a12, sp, XT_STK_TMP0 /* recover stuff from stack frame */ 180 l32i a13, sp, XT_STK_TMP1 181 l32i a9, sp, XT_STK_TMP2 182 #endif 183 184 #if XCHAL_EXTRA_SA_SIZE > 0 185 /* 186 NOTE: Normally the xthal_save_extra_nw macro only affects address 187 registers a2-a5. It is theoretically possible for Xtensa processor 188 designers to write TIE that causes more address registers to be 189 affected, but it is generally unlikely. If that ever happens, 190 more registers need to be saved/restored around this macro invocation. 191 Here we assume a9,12,13 are preserved. 192 Future Xtensa tools releases might limit the regs that can be affected. 193 */ 194 addi a2, sp, XT_STK_EXTRA /* where to save it */ 195 # if XCHAL_EXTRA_SA_ALIGN > 16 196 movi a3, -XCHAL_EXTRA_SA_ALIGN 197 and a2, a2, a3 /* align dynamically >16 bytes */ 198 # endif 199 call0 xthal_save_extra_nw /* destroys a0,2,3,4,5 */ 200 #endif 201 202 #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__) 203 mov a0, a9 /* retrieve ret addr */ 204 #endif 205 206 ret 207 208/******************************************************************************* 209 210_xt_context_restore 211 212 !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !! 213 214Restores all Xtensa processor state except PC, PS, A0, A1 (SP) (and in Call0 215ABI, A14, A15 which are preserved by all interrupt handlers) from an interrupt 216stack frame defined in xtensa_rtos.h . 217Its counterpart is _xt_context_save (whose caller saved A12, A13). 218 219Caller is responsible to restore PC, PS, A0, A1 (SP). 220 221Entry Conditions: 222 A0 = Return address in caller. 223 A1 = Stack pointer of interrupted thread or handler ("interruptee"). 224 225Exit conditions: 226 A0 = Return address in caller. 227 A1 = Stack pointer of interrupted thread or handler ("interruptee"). 228 Other processor state except PC, PS, A0, A1 (SP), is as at the point 229 of interruption. 230 231*******************************************************************************/ 232 233 .global _xt_context_restore 234 .type _xt_context_restore,@function 235 .align 4 236_xt_context_restore: 237 238 #if XCHAL_EXTRA_SA_SIZE > 0 239 /* 240 NOTE: Normally the xthal_restore_extra_nw macro only affects address 241 registers a2-a5. It is theoretically possible for Xtensa processor 242 designers to write TIE that causes more address registers to be 243 affected, but it is generally unlikely. If that ever happens, 244 more registers need to be saved/restored around this macro invocation. 245 Here we only assume a13 is preserved. 246 Future Xtensa tools releases might limit the regs that can be affected. 247 */ 248 mov a13, a0 /* preserve ret addr */ 249 addi a2, sp, XT_STK_EXTRA /* where to find it */ 250 # if XCHAL_EXTRA_SA_ALIGN > 16 251 movi a3, -XCHAL_EXTRA_SA_ALIGN 252 and a2, a2, a3 /* align dynamically >16 bytes */ 253 # endif 254 call0 xthal_restore_extra_nw /* destroys a0,2,3,4,5 */ 255 mov a0, a13 /* retrieve ret addr */ 256 #endif 257 258 #if XCHAL_HAVE_LOOPS 259 l32i a2, sp, XT_STK_LBEG 260 l32i a3, sp, XT_STK_LEND 261 wsr a2, LBEG 262 l32i a2, sp, XT_STK_LCOUNT 263 wsr a3, LEND 264 wsr a2, LCOUNT 265 #endif 266 267 #if XCHAL_HAVE_EXCLUSIVE 268 /* Restore state of ATOMCTL */ 269 l32i a2, sp, XT_STK_ATOMCTL 270 getex a2 271 #endif 272 273 #ifdef XT_USE_OVLY 274 /* 275 If we are using overlays, this is a good spot to check if we need 276 to restore an overlay for the incoming task. Here we have a bunch 277 of registers to spare. Note that this step is going to use a few 278 bytes of storage below SP (SP-20 to SP-32) if an overlay is going 279 to be restored. 280 */ 281 l32i a2, sp, XT_STK_PC /* retrieve PC */ 282 l32i a3, sp, XT_STK_PS /* retrieve PS */ 283 l32i a4, sp, XT_STK_OVLY /* retrieve overlay state */ 284 l32i a5, sp, XT_STK_A1 /* retrieve stack ptr */ 285 _xt_overlay_check_map a2, a3, a4, a5, a6 286 s32i a2, sp, XT_STK_PC /* save updated PC */ 287 s32i a3, sp, XT_STK_PS /* save updated PS */ 288 #endif 289 290 #ifdef XT_USE_SWPRI 291 /* Restore virtual interrupt priority and interrupt enable */ 292 movi a3, _xt_intdata 293 l32i a4, a3, 0 /* a4 = _xt_intenable */ 294 l32i a5, sp, XT_STK_VPRI /* a5 = saved _xt_vpri_mask */ 295 and a4, a4, a5 296 wsr a4, INTENABLE /* update INTENABLE */ 297 s32i a5, a3, 4 /* restore _xt_vpri_mask */ 298 #endif 299 300 l32i a3, sp, XT_STK_SAR 301 l32i a2, sp, XT_STK_A2 302 wsr a3, SAR 303 l32i a3, sp, XT_STK_A3 304 l32i a4, sp, XT_STK_A4 305 l32i a5, sp, XT_STK_A5 306 l32i a6, sp, XT_STK_A6 307 l32i a7, sp, XT_STK_A7 308 l32i a8, sp, XT_STK_A8 309 l32i a9, sp, XT_STK_A9 310 l32i a10, sp, XT_STK_A10 311 l32i a11, sp, XT_STK_A11 312 313 /* 314 Call0 ABI callee-saved regs a12-15 do not need to be restored here. 315 However a12-13 were saved for scratch before XT_RTOS_INT_ENTER(), 316 so need to be restored anyway, despite being callee-saved in Call0. 317 */ 318 l32i a12, sp, XT_STK_A12 319 l32i a13, sp, XT_STK_A13 320 #ifndef __XTENSA_CALL0_ABI__ 321 l32i a14, sp, XT_STK_A14 322 l32i a15, sp, XT_STK_A15 323 #endif 324 325 ret 326 327#endif /* XCHAL_HAVE_XEA3 */ 328 329 330/******************************************************************************* 331 332_xt_coproc_init 333 334Initializes global co-processor management data, setting all co-processors 335to "unowned". Leaves CPENABLE as it found it (does NOT clear it). 336 337Called during initialization of the RTOS, before any threads run. 338 339This may be called from normal Xtensa single-threaded application code which 340might use co-processors. The Xtensa run-time initialization enables all 341co-processors. They must remain enabled here, else a co-processor exception 342might occur outside of a thread, which the exception handler doesn't expect. 343 344Entry Conditions: 345 Xtensa single-threaded run-time environment is in effect. 346 No thread is yet running. 347 348Exit conditions: 349 None. 350 351Obeys ABI conventions per prototype: 352 void _xt_coproc_init(void) 353 354*******************************************************************************/ 355 356#if XCHAL_CP_NUM > 0 357 358 .global _xt_coproc_init 359 .type _xt_coproc_init,@function 360 .align 4 361_xt_coproc_init: 362 ENTRY0 363 364 /* Initialize thread co-processor ownerships to 0 (unowned). */ 365 movi a2, _xt_coproc_owner_sa /* a2 = base of owner array */ 366 addi a3, a2, XCHAL_CP_MAX << 2 /* a3 = top+1 of owner array */ 367 movi a4, 0 /* a4 = 0 (unowned) */ 3681: s32i a4, a2, 0 369 addi a2, a2, 4 370 bltu a2, a3, 1b 371 372 RET0 373 374#endif 375 376 377/******************************************************************************* 378 379_xt_coproc_release 380 381Releases any and all co-processors owned by a given thread. The thread is 382identified by it's co-processor state save area defined in xtensa_context.h . 383 384Must be called before a thread's co-proc save area is deleted to avoid 385memory corruption when the exception handler tries to save the state. 386May be called when a thread terminates or completes but does not delete 387the co-proc save area, to avoid the exception handler having to save the 388thread's co-proc state before another thread can use it (optimization). 389 390Entry Conditions: 391 A2 = Pointer to base of co-processor state save area. 392 393Exit conditions: 394 None. 395 396Obeys ABI conventions per prototype: 397 void _xt_coproc_release(void * coproc_sa_base) 398 399*******************************************************************************/ 400 401#if XCHAL_CP_NUM > 0 402 403 .global _xt_coproc_release 404 .type _xt_coproc_release,@function 405 .align 4 406_xt_coproc_release: 407 ENTRY0 /* a2 = base of save area */ 408 409 movi a3, _xt_coproc_owner_sa /* a3 = base of owner array */ 410 addi a4, a3, XCHAL_CP_MAX << 2 /* a4 = top+1 of owner array */ 411 movi a5, 0 /* a5 = 0 (unowned) */ 412 413#if XCHAL_HAVE_XEA3 414 movi a6, PS_DI 415 xps a6, a6 /* lock interrupts */ 416#else 417 rsil a6, XCHAL_EXCM_LEVEL /* lock interrupts */ 418#endif 419 4201: l32i a7, a3, 0 /* a7 = owner at a3 */ 421 bne a2, a7, 2f /* if (coproc_sa_base == owner) */ 422 s32i a5, a3, 0 /* owner = unowned */ 4232: addi a3, a3, 1<<2 /* a3 = next entry in owner array */ 424 bltu a3, a4, 1b /* repeat until end of array */ 425 4263: 427 wsr a6, PS /* restore interrupts */ 428 rsync 429 430 RET0 431 432#endif 433 434