1 /* 2 * Copyright (c) 2017, Intel Corporation 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 #ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_CONTEXT_H_ 7 #define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_CONTEXT_H_ 8 9 #if defined(__XT_CLANG__) 10 #include <xtensa/xtensa-types.h> 11 #endif 12 13 #include <xtensa/corebits.h> 14 #include <xtensa/config/core-isa.h> 15 #include <xtensa/config/tie.h> 16 17 /* 18 * Stack frame layout for a saved processor context, in memory order, 19 * high to low address: 20 * 21 * SP-0 <-- Interrupted stack pointer points here 22 * 23 * SP-4 Caller A3 spill slot \ 24 * SP-8 Caller A2 spill slot | 25 * SP-12 Caller A1 spill slot + (Part of ABI standard) 26 * SP-16 Caller A0 spill slot / 27 * 28 * SP-20 Saved A3 29 * SP-24 Saved A2 30 * SP-28 Unused (not "Saved A1" because the SP is saved externally as a handle) 31 * SP-32 Saved A0 32 * 33 * SP-36 Saved PC (address to jump to following restore) 34 * SP-40 Saved/interrupted PS special register 35 * 36 * SP-44 Saved SAR special register 37 * 38 * SP-48 Saved LBEG special register (if loops enabled) 39 * SP-52 Saved LEND special register (if loops enabled) 40 * SP-56 Saved LCOUNT special register (if loops enabled) 41 * 42 * SP-60 Saved SCOMPARE special register (if S32C1I enabled) 43 * 44 * SP-64 Saved EXCCAUSE special register 45 * 46 * SP-68 Saved THREADPTR special register (if processor has thread pointer) 47 * 48 * (The above fixed-size region is known as the "base save area" in the 49 * code below) 50 * 51 * - 18 FPU registers (if FPU is present and CONFIG_FPU_SHARING enabled) 52 * 53 * - Saved A7 \ 54 * - Saved A6 | 55 * - Saved A5 +- If not in-use by another frame 56 * - Saved A4 / 57 * 58 * - Saved A11 \ 59 * - Saved A10 | 60 * - Saved A9 +- If not in-use by another frame 61 * - Saved A8 / 62 * 63 * - Saved A15 \ 64 * - Saved A14 | 65 * - Saved A13 +- If not in-use by another frame 66 * - Saved A12 / 67 * 68 * - Saved intermediate stack pointer (points to low word of base save 69 * area, i.e. the saved LCOUNT or SAR). The pointer to this value 70 * (i.e. the final stack pointer) is stored externally as the 71 * "restore handle" in the thread context. 72 * 73 * Essentially, you can recover a pointer to the BSA by loading *SP. 74 * Adding the fixed BSA size to that gets you back to the 75 * original/interrupted stack pointer. 76 */ 77 78 #ifndef __ASSEMBLER__ 79 80 #include <stdint.h> 81 #include <zephyr/toolchain.h> 82 83 /* Stack needs to aligned on 16-bytes as mentioned on Xtensa ISA. 84 * So we pad _xtensa_irq_bsa_t to achieve that. The followings 85 * are see how much space is taken depending on features enabled. 86 */ 87 88 #if XCHAL_HAVE_FP && defined(CONFIG_CPU_HAS_FPU) && defined(CONFIG_FPU_SHARING) 89 # define _BSA_PADDING_FPU (sizeof(uintptr_t) * 18U) 90 #else 91 # define _BSA_PADDING_FPU (0) 92 #endif 93 94 #if defined(CONFIG_XTENSA_EAGER_HIFI_SHARING) 95 # define _BSA_PADDING_HIFI (XCHAL_CP1_SA_SIZE + XCHAL_CP1_SA_ALIGN) 96 #else 97 # define _BSA_PADDING_HIFI (0) 98 #endif 99 100 #if XCHAL_HAVE_THREADPTR 101 # define _BSA_PADDING_THREADPTR (sizeof(uintptr_t)) 102 #else 103 # define _BSA_PADDING_THREADPTR (0) 104 #endif 105 106 #if XCHAL_HAVE_S32C1I 107 # define _BSA_PADDING_S32C1I (sizeof(uintptr_t)) 108 #else 109 # define _BSA_PADDING_S32C1I (0) 110 #endif 111 112 #if XCHAL_HAVE_LOOPS 113 # define _BSA_PADDING_LOOPS (sizeof(uintptr_t) * 3U) 114 #else 115 # define _BSA_PADDING_LOOPS (0) 116 #endif 117 118 /* Must have fields regardless of features. */ 119 #define _BSA_PADDING_COMMON (sizeof(uintptr_t) * 12U) 120 121 /* Raw size by adding up all the above. */ 122 #define _BSA_PADDING_BASE_SIZE \ 123 (_BSA_PADDING_FPU + \ 124 _BSA_PADDING_HIFI + \ 125 _BSA_PADDING_THREADPTR + \ 126 _BSA_PADDING_S32C1I + \ 127 _BSA_PADDING_LOOPS + \ 128 _BSA_PADDING_COMMON) 129 130 /* Each stack frame always has a pointer to BSA so we add 131 * that (+4) to the BSA size before padding the BSA to have 132 * size aligned on 16 bytes. Each group of high registers to 133 * be saved (totally 3 groups) consists of 4 registers which 134 * are 16 bytes already. So each type of stack frame 135 * (A[3, 7, 11, 15]) do not need any further padding as long 136 * as the BSA struct is of correct size. 137 */ 138 #define _BSA_PADDING_PADDED_SIZE \ 139 ((((_BSA_PADDING_BASE_SIZE + 4) + 15) / 16 * 16) - 4) 140 141 /* How many extra bytes needed. */ 142 #define _BSA_PADDING_NEEDED \ 143 (_BSA_PADDING_PADDED_SIZE - _BSA_PADDING_BASE_SIZE) 144 145 /** 146 * Base Save Area (BSA) during interrupt. 147 * 148 * This saves the registers during interrupt entrance 149 * so they can be restored later. 150 * 151 * Note that only A0-A3 are saved here. High registers 152 * are saved after the BSA. 153 */ 154 struct xtensa_irq_base_save_area { 155 #if XCHAL_HAVE_FP && defined(CONFIG_CPU_HAS_FPU) && defined(CONFIG_FPU_SHARING) 156 uintptr_t fcr; 157 uintptr_t fsr; 158 uintptr_t fpu0; 159 uintptr_t fpu1; 160 uintptr_t fpu2; 161 uintptr_t fpu3; 162 uintptr_t fpu4; 163 uintptr_t fpu5; 164 uintptr_t fpu6; 165 uintptr_t fpu7; 166 uintptr_t fpu8; 167 uintptr_t fpu9; 168 uintptr_t fpu10; 169 uintptr_t fpu11; 170 uintptr_t fpu12; 171 uintptr_t fpu13; 172 uintptr_t fpu14; 173 uintptr_t fpu15; 174 #endif 175 176 #if defined(CONFIG_XTENSA_EAGER_HIFI_SHARING) 177 178 /* 179 * Carve space for the registers used by the HiFi audio engine 180 * coprocessor (which is always CP1). Carve additional space to 181 * manage alignment at run-time as we can not yet guarantee the 182 * alignment of the BSA. 183 */ 184 185 uint8_t hifi[XCHAL_CP1_SA_SIZE + XCHAL_CP1_SA_ALIGN]; 186 #endif 187 188 #if XCHAL_HAVE_THREADPTR 189 uintptr_t threadptr; 190 #endif 191 192 #if XCHAL_HAVE_S32C1I 193 uintptr_t scompare1; 194 #endif 195 196 uintptr_t exccause; 197 198 #if XCHAL_HAVE_LOOPS 199 uintptr_t lcount; 200 uintptr_t lend; 201 uintptr_t lbeg; 202 #endif 203 204 uintptr_t sar; 205 uintptr_t ps; 206 uintptr_t pc; 207 uintptr_t a0; 208 uintptr_t scratch; 209 uintptr_t a2; 210 uintptr_t a3; 211 212 uintptr_t padding[_BSA_PADDING_NEEDED / sizeof(uintptr_t)]; 213 214 uintptr_t caller_a0; 215 uintptr_t caller_a1; 216 uintptr_t caller_a2; 217 uintptr_t caller_a3; 218 }; 219 220 typedef struct xtensa_irq_base_save_area _xtensa_irq_bsa_t; 221 222 #undef _BSA_PADDING_NEEDED 223 #undef _BSA_PADDING_PADDED_SIZE 224 #undef _BSA_PADDING_BASE_SIZE 225 #undef _BSA_PADDING_COMMON 226 #undef _BSA_PADDING_LOOPS 227 #undef _BSA_PADDING_S32C1I 228 #undef _BSA_PADDING_THREADPTR 229 #undef _BSA_PADDING_HIFI 230 #undef _BSA_PADDING_FPU 231 232 /** 233 * Raw interrupt stack frame. 234 * 235 * This provides a raw interrupt stack frame to make it 236 * easier to construct general purpose code in loops. 237 * Avoid using this if possible. 238 */ 239 struct xtensa_irq_stack_frame_raw { 240 _xtensa_irq_bsa_t *ptr_to_bsa; 241 242 struct { 243 uintptr_t r0; 244 uintptr_t r1; 245 uintptr_t r2; 246 uintptr_t r3; 247 } blks[3]; 248 }; 249 250 typedef struct xtensa_irq_stack_frame_raw _xtensa_irq_stack_frame_raw_t; 251 252 /** 253 * Interrupt stack frame containing A0 - A15. 254 */ 255 struct xtensa_irq_stack_frame_a15 { 256 _xtensa_irq_bsa_t *ptr_to_bsa; 257 258 uintptr_t a12; 259 uintptr_t a13; 260 uintptr_t a14; 261 uintptr_t a15; 262 263 uintptr_t a8; 264 uintptr_t a9; 265 uintptr_t a10; 266 uintptr_t a11; 267 268 uintptr_t a4; 269 uintptr_t a5; 270 uintptr_t a6; 271 uintptr_t a7; 272 273 _xtensa_irq_bsa_t bsa; 274 }; 275 276 typedef struct xtensa_irq_stack_frame_a15 _xtensa_irq_stack_frame_a15_t; 277 278 /** 279 * Interrupt stack frame containing A0 - A11. 280 */ 281 struct xtensa_irq_stack_frame_a11 { 282 _xtensa_irq_bsa_t *ptr_to_bsa; 283 284 uintptr_t a8; 285 uintptr_t a9; 286 uintptr_t a10; 287 uintptr_t a11; 288 289 uintptr_t a4; 290 uintptr_t a5; 291 uintptr_t a6; 292 uintptr_t a7; 293 294 _xtensa_irq_bsa_t bsa; 295 }; 296 297 typedef struct xtensa_irq_stack_frame_a11 _xtensa_irq_stack_frame_a11_t; 298 299 /** 300 * Interrupt stack frame containing A0 - A7. 301 */ 302 struct xtensa_irq_stack_frame_a7 { 303 _xtensa_irq_bsa_t *ptr_to_bsa; 304 305 uintptr_t a4; 306 uintptr_t a5; 307 uintptr_t a6; 308 uintptr_t a7; 309 310 _xtensa_irq_bsa_t bsa; 311 }; 312 313 typedef struct xtensa_irq_stack_frame_a7 _xtensa_irq_stack_frame_a7_t; 314 315 /** 316 * Interrupt stack frame containing A0 - A3. 317 */ 318 struct xtensa_irq_stack_frame_a3 { 319 _xtensa_irq_bsa_t *ptr_to_bsa; 320 321 _xtensa_irq_bsa_t bsa; 322 }; 323 324 typedef struct xtensa_irq_stack_frame_a3 _xtensa_irq_stack_frame_a3_t; 325 326 #endif /* __ASSEMBLER__ */ 327 328 #endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_CONTEXT_H_ */ 329