1 /* Assembly functions for libgcc2. 2 Copyright (C) 2001-2024 Free Software Foundation, Inc. 3 Contributed by Bob Wilson (bwilson (at) tensilica.com) at Tensilica. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it under 8 the terms of the GNU General Public License as published by the Free 9 Software Foundation; either version 3, or (at your option) any later 10 version. 11 12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 for more details. 16 17 Under Section 7 of GPL version 3, you are granted additional 18 permissions described in the GCC Runtime Library Exception, version 19 3.1, as published by the Free Software Foundation. 20 21 You should have received a copy of the GNU General Public License and 22 a copy of the GCC Runtime Library Exception along with this program; 23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 <http://www.gnu.org/licenses/>. */ 25 26 #include "xtensa-config-builtin.h" 27 28 /* An executable stack is *not* required for these functions. */ 29 #if defined(__ELF__) && defined(__linux__) 30 .section .note.GNU-stack,"",%progbits 31 .previous 32 #endif 33 34 /* __xtensa_libgcc_window_spill: This function flushes out all but the 35 current register window. This is used to set up the stack so that 36 arbitrary frames can be accessed. */ 37 38 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 39 .align 4 40 .global __xtensa_libgcc_window_spill 41 .type __xtensa_libgcc_window_spill,@function 42 __xtensa_libgcc_window_spill: 43 entry sp, 48 44 #if XCHAL_NUM_AREGS > 16 45 call12 1f 46 retw 47 .align 4 48 1: 49 .rept (XCHAL_NUM_AREGS - 24) / 12 50 _entry sp, 48 51 mov a12, a0 52 .endr 53 _entry sp, 16 54 #if XCHAL_NUM_AREGS % 12 == 0 55 mov a4, a4 56 #elif XCHAL_NUM_AREGS % 12 == 4 57 mov a8, a8 58 #elif XCHAL_NUM_AREGS % 12 == 8 59 mov a12, a12 60 #endif 61 retw 62 #else 63 mov a8, a8 64 retw 65 #endif 66 .size __xtensa_libgcc_window_spill, .-__xtensa_libgcc_window_spill 67 #endif 68 69 70 /* __xtensa_nonlocal_goto: This code does all the hard work of a 71 nonlocal goto on Xtensa. It is here in the library to avoid the 72 code size bloat of generating it in-line. There are two 73 arguments: 74 75 a2 = frame pointer for the procedure containing the label 76 a3 = goto handler address 77 78 This function never returns to its caller but instead goes directly 79 to the address of the specified goto handler. */ 80 81 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 82 .align 4 83 .global __xtensa_nonlocal_goto 84 .type __xtensa_nonlocal_goto,@function 85 __xtensa_nonlocal_goto: 86 entry sp, 32 87 88 /* Flush registers. */ 89 call8 __xtensa_libgcc_window_spill 90 91 /* Because the save area for a0-a3 is stored one frame below 92 the one identified by a2, the only way to restore those 93 registers is to unwind the stack. If alloca() were never 94 called, we could just unwind until finding the sp value 95 matching a2. However, a2 is a frame pointer, not a stack 96 pointer, and may not be encountered during the unwinding. 97 The solution is to unwind until going _past_ the value 98 given by a2. This involves keeping three stack pointer 99 values during the unwinding: 100 101 next = sp of frame N-1 102 cur = sp of frame N 103 prev = sp of frame N+1 104 105 When next > a2, the desired save area is stored relative 106 to prev. At this point, cur will be the same as a2 107 except in the alloca() case. 108 109 Besides finding the values to be restored to a0-a3, we also 110 need to find the current window size for the target 111 function. This can be extracted from the high bits of the 112 return address, initially in a0. As the unwinding 113 proceeds, the window size is taken from the value of a0 114 saved _two_ frames below the current frame. */ 115 116 addi a5, sp, -16 /* a5 = prev - save area */ 117 l32i a6, a5, 4 118 addi a6, a6, -16 /* a6 = cur - save area */ 119 mov a8, a0 /* a8 = return address (for window size) */ 120 j .Lfirstframe 121 122 .Lnextframe: 123 l32i a8, a5, 0 /* next return address (for window size) */ 124 mov a5, a6 /* advance prev */ 125 addi a6, a7, -16 /* advance cur */ 126 .Lfirstframe: 127 l32i a7, a6, 4 /* a7 = next */ 128 bgeu a2, a7, .Lnextframe 129 130 /* At this point, prev (a5) points to the save area with the saved 131 values of a0-a3. Copy those values into the save area at the 132 current sp so they will be reloaded when the return from this 133 function underflows. We don't have to worry about exceptions 134 while updating the current save area, because the windows have 135 already been flushed. */ 136 137 addi a4, sp, -16 /* a4 = save area of this function */ 138 l32i a6, a5, 0 139 l32i a7, a5, 4 140 s32i a6, a4, 0 141 s32i a7, a4, 4 142 l32i a6, a5, 8 143 l32i a7, a5, 12 144 s32i a6, a4, 8 145 s32i a7, a4, 12 146 147 /* Set return address to goto handler. Use the window size bits 148 from the return address two frames below the target. */ 149 extui a8, a8, 30, 2 /* get window size from return addr. */ 150 slli a3, a3, 2 /* get goto handler addr. << 2 */ 151 ssai 2 152 src a0, a8, a3 /* combine them with a funnel shift */ 153 154 retw 155 .size __xtensa_nonlocal_goto, .-__xtensa_nonlocal_goto 156 #endif 157 158 159 /* __xtensa_sync_caches: This function is called after writing a trampoline 160 on the stack to force all the data writes to memory and invalidate the 161 instruction cache. a2 is the address of the new trampoline. 162 163 After the trampoline data is written out, it must be flushed out of 164 the data cache into memory. We use DHWB in case we have a writeback 165 cache. At least one DHWB instruction is needed for each data cache 166 line which may be touched by the trampoline. An ISYNC instruction 167 must follow the DHWBs. 168 169 We have to flush the i-cache to make sure that the new values get used. 170 At least one IHI instruction is needed for each i-cache line which may 171 be touched by the trampoline. An ISYNC instruction is also needed to 172 make sure that the modified instructions are loaded into the instruction 173 fetch buffer. */ 174 175 /* Use the maximum trampoline size. Flushing a bit extra is OK. */ 176 #define TRAMPOLINE_SIZE 60 177 178 .text 179 .align 4 180 .global __xtensa_sync_caches 181 .type __xtensa_sync_caches,@function 182 __xtensa_sync_caches: 183 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 184 entry sp, 32 185 #endif 186 #if XCHAL_DCACHE_SIZE > 0 187 /* Flush the trampoline from the data cache. */ 188 extui a4, a2, 0, XCHAL_DCACHE_LINEWIDTH 189 addi a4, a4, TRAMPOLINE_SIZE 190 addi a4, a4, (1 << XCHAL_DCACHE_LINEWIDTH) - 1 191 srli a4, a4, XCHAL_DCACHE_LINEWIDTH 192 mov a3, a2 193 .Ldcache_loop: 194 dhwb a3, 0 195 addi a3, a3, (1 << XCHAL_DCACHE_LINEWIDTH) 196 addi a4, a4, -1 197 bnez a4, .Ldcache_loop 198 isync 199 #endif 200 #if XCHAL_ICACHE_SIZE > 0 201 /* Invalidate the corresponding lines in the instruction cache. */ 202 extui a4, a2, 0, XCHAL_ICACHE_LINEWIDTH 203 addi a4, a4, TRAMPOLINE_SIZE 204 addi a4, a4, (1 << XCHAL_ICACHE_LINEWIDTH) - 1 205 srli a4, a4, XCHAL_ICACHE_LINEWIDTH 206 .Licache_loop: 207 ihi a2, 0 208 addi a2, a2, (1 << XCHAL_ICACHE_LINEWIDTH) 209 addi a4, a4, -1 210 bnez a4, .Licache_loop 211 #endif 212 isync 213 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 214 retw 215 #else 216 ret 217 #endif 218 .size __xtensa_sync_caches, .-__xtensa_sync_caches 219