1 /*******************************************************************************
2 Copyright (c) 2006-2015 Cadence Design Systems Inc.
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:
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
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 --------------------------------------------------------------------------------
24 XTENSA CONTEXT SAVE AND RESTORE ROUTINES
26 Low-level Call0 functions for handling generic context save and restore of
27 registers not specifically addressed by the interrupt vectors and handlers.
28 Those registers (not handled by these functions) are PC, PS, A0, A1 (SP).
29 Except for the calls to RTOS functions, this code is generic to Xtensa.
31 Note that in Call0 ABI, interrupt handlers are expected to preserve the callee-
32 save regs (A12-A15), which is always the case if the handlers are coded in C.
33 However A12, A13 are made available as scratch registers for interrupt dispatch
34 code, so are presumed saved anyway, and are always restored even in Call0 ABI.
35 Only A14, A15 are truly handled as callee-save regs.
37 Because Xtensa is a configurable architecture, this port supports all user
38 generated configurations (except restrictions stated in the release notes).
39 This is accomplished by conditional compilation using macros and functions
40 defined in the Xtensa HAL (hardware adaptation layer) for your configuration.
41 Only the processor state included in your configuration is saved and restored,
42 including any processor state added by user configuration options or TIE.
44 *******************************************************************************/
46 /* Warn nicely if this file gets named with a lowercase .s instead of .S: */
48 NOERROR: .error "C preprocessor needed for this file: make sure its filename\
49 ends in uppercase .S, or use xt-xcc's -x assembler-with-cpp option."
52 #include "xtensa_rtos.h"
53 #include "xtensa_context.h"
56 #include <xtensa/overlay_os_asm.h>
63 /*******************************************************************************
67 !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!
69 Saves all Xtensa processor state except PC, PS, A0, A1 (SP), A12, A13, in the
70 interrupt stack frame defined in xtensa_rtos.h.
71 Its counterpart is _xt_context_restore (which also restores A12, A13).
73 Caller is expected to have saved PC, PS, A0, A1 (SP), A12, A13 in the frame.
74 This function preserves A12 & A13 in order to provide the caller with 2 scratch
75 regs that need not be saved over the call to this function. The choice of which
76 2 regs to provide is governed by xthal_window_spill_nw and xthal_save_extra_nw,
77 to avoid moving data more than necessary. Caller can assign regs accordingly.
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).
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).
93 *******************************************************************************/
95 .global _xt_context_save
96 .type _xt_context_save,@function
102 s32i a2, sp, XT_STK_A2
103 s32i a3, sp, XT_STK_A3
104 s32i a4, sp, XT_STK_A4
105 s32i a5, sp, XT_STK_A5
106 s32i a6, sp, XT_STK_A6
107 s32i a7, sp, XT_STK_A7
108 s32i a8, sp, XT_STK_A8
109 s32i a9, sp, XT_STK_A9
110 s32i a10, sp, XT_STK_A10
111 s32i a11, sp, XT_STK_A11
114 Call0 ABI callee-saved regs a12-15 do not need to be saved here.
115 a12-13 are the caller's responsibility so it can use them as scratch.
116 So only need to save a14-a15 here for Windowed ABI (not Call0).
118 #ifndef __XTENSA_CALL0_ABI__
119 s32i a14, sp, XT_STK_A14
120 s32i a15, sp, XT_STK_A15
124 s32i a3, sp, XT_STK_SAR
128 s32i a3, sp, XT_STK_LBEG
130 s32i a3, sp, XT_STK_LEND
132 s32i a3, sp, XT_STK_LCOUNT
136 /* Save virtual priority mask */
137 movi a3, _xt_vpri_mask
139 s32i a3, sp, XT_STK_VPRI
142 #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__)
143 mov a9, a0 /* preserve ret addr */
146 #ifndef __XTENSA_CALL0_ABI__
148 To spill the reg windows, temp. need pre-interrupt stack ptr and a4-15.
149 Need to save a9,12,13 temporarily (in frame temps) and recover originals.
150 Interrupts need to be disabled below XCHAL_EXCM_LEVEL and window overflow
151 and underflow exceptions disabled (assured by PS.EXCM == 1).
153 s32i a12, sp, XT_STK_TMP0 /* temp. save stuff in stack frame */
154 s32i a13, sp, XT_STK_TMP1
155 s32i a9, sp, XT_STK_TMP2
158 Save the overlay state if we are supporting overlays. Since we just saved
159 three registers, we can conveniently use them here. Note that as of now,
160 overlays only work for windowed calling ABI.
163 l32i a9, sp, XT_STK_PC /* recover saved PC */
164 _xt_overlay_get_state a9, a12, a13
165 s32i a9, sp, XT_STK_OVLY /* save overlay state */
168 l32i a12, sp, XT_STK_A12 /* recover original a9,12,13 */
169 l32i a13, sp, XT_STK_A13
170 l32i a9, sp, XT_STK_A9
171 addi sp, sp, XT_STK_FRMSZ /* restore the interruptee's SP */
172 call0 xthal_window_spill_nw /* preserves only a4,5,8,9,12,13 */
173 addi sp, sp, -XT_STK_FRMSZ
174 l32i a12, sp, XT_STK_TMP0 /* recover stuff from stack frame */
175 l32i a13, sp, XT_STK_TMP1
176 l32i a9, sp, XT_STK_TMP2
179 #if XCHAL_EXTRA_SA_SIZE > 0
181 NOTE: Normally the xthal_save_extra_nw macro only affects address
182 registers a2-a5. It is theoretically possible for Xtensa processor
183 designers to write TIE that causes more address registers to be
184 affected, but it is generally unlikely. If that ever happens,
185 more registers need to be saved/restored around this macro invocation.
186 Here we assume a9,12,13 are preserved.
187 Future Xtensa tools releases might limit the regs that can be affected.
189 addi a2, sp, XT_STK_EXTRA /* where to save it */
190 # if XCHAL_EXTRA_SA_ALIGN > 16
191 movi a3, -XCHAL_EXTRA_SA_ALIGN
192 and a2, a2, a3 /* align dynamically >16 bytes */
194 call0 xthal_save_extra_nw /* destroys a0,2,3,4,5 */
197 #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__)
198 mov a0, a9 /* retrieve ret addr */
203 /*******************************************************************************
207 !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!
209 Restores all Xtensa processor state except PC, PS, A0, A1 (SP) (and in Call0
210 ABI, A14, A15 which are preserved by all interrupt handlers) from an interrupt
211 stack frame defined in xtensa_rtos.h .
212 Its counterpart is _xt_context_save (whose caller saved A12, A13).
214 Caller is responsible to restore PC, PS, A0, A1 (SP).
217 A0 = Return address in caller.
218 A1 = Stack pointer of interrupted thread or handler ("interruptee").
221 A0 = Return address in caller.
222 A1 = Stack pointer of interrupted thread or handler ("interruptee").
223 Other processor state except PC, PS, A0, A1 (SP), is as at the point
226 *******************************************************************************/
228 .global _xt_context_restore
229 .type _xt_context_restore,@function
235 #if XCHAL_EXTRA_SA_SIZE > 0
237 NOTE: Normally the xthal_restore_extra_nw macro only affects address
238 registers a2-a5. It is theoretically possible for Xtensa processor
239 designers to write TIE that causes more address registers to be
240 affected, but it is generally unlikely. If that ever happens,
241 more registers need to be saved/restored around this macro invocation.
242 Here we only assume a13 is preserved.
243 Future Xtensa tools releases might limit the regs that can be affected.
245 mov a13, a0 /* preserve ret addr */
246 addi a2, sp, XT_STK_EXTRA /* where to find it */
247 # if XCHAL_EXTRA_SA_ALIGN > 16
248 movi a3, -XCHAL_EXTRA_SA_ALIGN
249 and a2, a2, a3 /* align dynamically >16 bytes */
251 call0 xthal_restore_extra_nw /* destroys a0,2,3,4,5 */
252 mov a0, a13 /* retrieve ret addr */
256 l32i a2, sp, XT_STK_LBEG
257 l32i a3, sp, XT_STK_LEND
259 l32i a2, sp, XT_STK_LCOUNT
266 If we are using overlays, this is a good spot to check if we need
267 to restore an overlay for the incoming task. Here we have a bunch
268 of registers to spare. Note that this step is going to use a few
269 bytes of storage below SP (SP-20 to SP-32) if an overlay is going
272 l32i a2, sp, XT_STK_PC /* retrieve PC */
273 l32i a3, sp, XT_STK_PS /* retrieve PS */
274 l32i a4, sp, XT_STK_OVLY /* retrieve overlay state */
275 l32i a5, sp, XT_STK_A1 /* retrieve stack ptr */
276 _xt_overlay_check_map a2, a3, a4, a5, a6
277 s32i a2, sp, XT_STK_PC /* save updated PC */
278 s32i a3, sp, XT_STK_PS /* save updated PS */
282 /* Restore virtual interrupt priority and interrupt enable */
284 l32i a4, a3, 0 /* a4 = _xt_intenable */
285 l32i a5, sp, XT_STK_VPRI /* a5 = saved _xt_vpri_mask */
287 wsr a4, INTENABLE /* update INTENABLE */
288 s32i a5, a3, 4 /* restore _xt_vpri_mask */
291 l32i a3, sp, XT_STK_SAR
292 l32i a2, sp, XT_STK_A2
294 l32i a3, sp, XT_STK_A3
295 l32i a4, sp, XT_STK_A4
296 l32i a5, sp, XT_STK_A5
297 l32i a6, sp, XT_STK_A6
298 l32i a7, sp, XT_STK_A7
299 l32i a8, sp, XT_STK_A8
300 l32i a9, sp, XT_STK_A9
301 l32i a10, sp, XT_STK_A10
302 l32i a11, sp, XT_STK_A11
305 Call0 ABI callee-saved regs a12-15 do not need to be restored here.
306 However a12-13 were saved for scratch before XT_RTOS_INT_ENTER(),
307 so need to be restored anyway, despite being callee-saved in Call0.
309 l32i a12, sp, XT_STK_A12
310 l32i a13, sp, XT_STK_A13
311 #ifndef __XTENSA_CALL0_ABI__
312 l32i a14, sp, XT_STK_A14
313 l32i a15, sp, XT_STK_A15
319 /*******************************************************************************
323 Initializes global co-processor management data, setting all co-processors
324 to "unowned". Leaves CPENABLE as it found it (does NOT clear it).
326 Called during initialization of the RTOS, before any threads run.
328 This may be called from normal Xtensa single-threaded application code which
329 might use co-processors. The Xtensa run-time initialization enables all
330 co-processors. They must remain enabled here, else a co-processor exception
331 might occur outside of a thread, which the exception handler doesn't expect.
334 Xtensa single-threaded run-time environment is in effect.
335 No thread is yet running.
340 Obeys ABI conventions per prototype:
341 void _xt_coproc_init(void)
343 *******************************************************************************/
347 .global _xt_coproc_init
348 .type _xt_coproc_init,@function
355 /* Initialize thread co-processor ownerships to 0 (unowned). */
356 movi a2, _xt_coproc_owner_sa /* a2 = base of owner array */
357 addi a3, a2, (XCHAL_CP_MAX*portNUM_PROCESSORS) << 2 /* a3 = top+1 of owner array */
358 movi a4, 0 /* a4 = 0 (unowned) */
368 /*******************************************************************************
372 Releases any and all co-processors owned by a given thread. The thread is
373 identified by it's co-processor state save area defined in xtensa_context.h .
375 Must be called before a thread's co-proc save area is deleted to avoid
376 memory corruption when the exception handler tries to save the state.
377 May be called when a thread terminates or completes but does not delete
378 the co-proc save area, to avoid the exception handler having to save the
379 thread's co-proc state before another thread can use it (optimization).
381 Needs to be called on the processor the thread was running on. Unpinned threads
382 won't have an entry here because they get pinned as soon they use a coprocessor.
385 A2 = Pointer to base of co-processor state save area.
390 Obeys ABI conventions per prototype:
391 void _xt_coproc_release(void * coproc_sa_base)
393 *******************************************************************************/
397 .global _xt_coproc_release
398 .type _xt_coproc_release,@function
403 ENTRY0 /* a2 = base of save area */
406 movi a3, XCHAL_CP_MAX << 2
408 movi a3, _xt_coproc_owner_sa /* a3 = base of owner array */
411 addi a4, a3, XCHAL_CP_MAX << 2 /* a4 = top+1 of owner array */
412 movi a5, 0 /* a5 = 0 (unowned) */
414 rsil a6, XCHAL_EXCM_LEVEL /* lock interrupts */
416 1: l32i a7, a3, 0 /* a7 = owner at a3 */
417 bne a2, a7, 2f /* if (coproc_sa_base == owner) */
418 s32i a5, a3, 0 /* owner = unowned */
419 2: addi a3, a3, 1<<2 /* a3 = next entry in owner array */
420 bltu a3, a4, 1b /* repeat until end of array */
422 3: wsr a6, PS /* restore interrupts */
429 /*******************************************************************************
432 If there is a current thread and it has a coprocessor state save area, then
433 save all callee-saved state into this area. This function is called from the
434 solicited context switch handler. It calls a system-specific function to get
435 the coprocessor save area base address.
438 - The thread being switched out is still the current thread.
439 - CPENABLE state reflects which coprocessors are active.
440 - Registers have been saved/spilled already.
443 - All necessary CP callee-saved state has been saved.
444 - Registers a2-a7, a13-a15 have been trashed.
446 Must be called from assembly code only, using CALL0.
447 *******************************************************************************/
450 .extern _xt_coproc_sa_offset /* external reference */
452 .global _xt_coproc_savecs
453 .type _xt_coproc_savecs,@function
459 /* At entry, CPENABLE should be showing which CPs are enabled. */
461 rsr a2, CPENABLE /* a2 = which CPs are enabled */
462 beqz a2, .Ldone /* quick exit if none */
463 mov a14, a0 /* save return address */
464 call0 XT_RTOS_CP_STATE /* get address of CP save area */
465 mov a0, a14 /* restore return address */
466 beqz a15, .Ldone /* if none then nothing to do */
467 s16i a2, a15, XT_CP_CS_ST /* save mask of CPs being stored */
468 movi a13, _xt_coproc_sa_offset /* array of CP save offsets */
469 l32i a15, a15, XT_CP_ASA /* a15 = base of aligned save area */
471 #if XCHAL_CP0_SA_SIZE
472 bbci.l a2, 0, 2f /* CP 0 not enabled */
473 l32i a14, a13, 0 /* a14 = _xt_coproc_sa_offset[0] */
474 add a3, a14, a15 /* a3 = save area for CP 0 */
475 xchal_cp0_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
479 #if XCHAL_CP1_SA_SIZE
480 bbci.l a2, 1, 2f /* CP 1 not enabled */
481 l32i a14, a13, 4 /* a14 = _xt_coproc_sa_offset[1] */
482 add a3, a14, a15 /* a3 = save area for CP 1 */
483 xchal_cp1_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
487 #if XCHAL_CP2_SA_SIZE
491 xchal_cp2_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
495 #if XCHAL_CP3_SA_SIZE
499 xchal_cp3_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
503 #if XCHAL_CP4_SA_SIZE
507 xchal_cp4_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
511 #if XCHAL_CP5_SA_SIZE
515 xchal_cp5_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
519 #if XCHAL_CP6_SA_SIZE
523 xchal_cp6_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
527 #if XCHAL_CP7_SA_SIZE
531 xchal_cp7_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
540 /*******************************************************************************
543 Restore any callee-saved coprocessor state for the incoming thread.
544 This function is called from coprocessor exception handling, when giving
545 ownership to a thread that solicited a context switch earlier. It calls a
546 system-specific function to get the coprocessor save area base address.
549 - The incoming thread is set as the current thread.
550 - CPENABLE is set up correctly for all required coprocessors.
551 - a2 = mask of coprocessors to be restored.
554 - All necessary CP callee-saved state has been restored.
555 - CPENABLE - unchanged.
556 - Registers a2-a7, a13-a15 have been trashed.
558 Must be called from assembly code only, using CALL0.
559 *******************************************************************************/
562 .global _xt_coproc_restorecs
563 .type _xt_coproc_restorecs,@function
567 _xt_coproc_restorecs:
569 mov a14, a0 /* save return address */
570 call0 XT_RTOS_CP_STATE /* get address of CP save area */
571 mov a0, a14 /* restore return address */
572 beqz a15, .Ldone2 /* if none then nothing to do */
573 l16ui a3, a15, XT_CP_CS_ST /* a3 = which CPs have been saved */
574 xor a3, a3, a2 /* clear the ones being restored */
575 s32i a3, a15, XT_CP_CS_ST /* update saved CP mask */
576 movi a13, _xt_coproc_sa_offset /* array of CP save offsets */
577 l32i a15, a15, XT_CP_ASA /* a15 = base of aligned save area */
579 #if XCHAL_CP0_SA_SIZE
580 bbci.l a2, 0, 2f /* CP 0 not enabled */
581 l32i a14, a13, 0 /* a14 = _xt_coproc_sa_offset[0] */
582 add a3, a14, a15 /* a3 = save area for CP 0 */
583 xchal_cp0_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
587 #if XCHAL_CP1_SA_SIZE
588 bbci.l a2, 1, 2f /* CP 1 not enabled */
589 l32i a14, a13, 4 /* a14 = _xt_coproc_sa_offset[1] */
590 add a3, a14, a15 /* a3 = save area for CP 1 */
591 xchal_cp1_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
595 #if XCHAL_CP2_SA_SIZE
599 xchal_cp2_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
603 #if XCHAL_CP3_SA_SIZE
607 xchal_cp3_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
611 #if XCHAL_CP4_SA_SIZE
615 xchal_cp4_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
619 #if XCHAL_CP5_SA_SIZE
623 xchal_cp5_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
627 #if XCHAL_CP6_SA_SIZE
631 xchal_cp6_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
635 #if XCHAL_CP7_SA_SIZE
639 xchal_cp7_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL