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