xref: /linux/arch/arc/include/asm/entry-arcv2.h (revision 4b660dbd9ee2059850fd30e0df420ca7a38a1856)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 
3 #ifndef __ASM_ARC_ENTRY_ARCV2_H
4 #define __ASM_ARC_ENTRY_ARCV2_H
5 
6 #include <asm/asm-offsets.h>
7 #include <asm/dsp-impl.h>
8 #include <asm/irqflags-arcv2.h>
9 #include <asm/thread_info.h>	/* For THREAD_SIZE */
10 
11 /*
12  * Interrupt/Exception stack layout (pt_regs) for ARCv2
13  *   (End of struct aligned to end of page [unless nested])
14  *
15  *  INTERRUPT                          EXCEPTION
16  *
17  *    manual    ---------------------  manual
18  *              |      orig_r0      |
19  *              |      event/ECR    |
20  *              |      bta          |
21  *              |      gp           |
22  *              |      fp           |
23  *              |      sp           |
24  *              |      r12          |
25  *              |      r30          |
26  *              |      r58          |
27  *              |      r59          |
28  *  hw autosave ---------------------
29  *    optional  |      r0           |
30  *              |      r1           |
31  *              ~                   ~
32  *              |      r9           |
33  *              |      r10          |
34  *              |      r11          |
35  *              |      blink        |
36  *              |      lpe          |
37  *              |      lps          |
38  *              |      lpc          |
39  *              |      ei base      |
40  *              |      ldi base     |
41  *              |      jli base     |
42  *              ---------------------
43  *  hw autosave |       pc / eret   |
44  *   mandatory  | stat32 / erstatus |
45  *              ---------------------
46  */
47 
48 /*------------------------------------------------------------------------*/
49 .macro INTERRUPT_PROLOGUE
50 
51 	; Before jumping to Interrupt Vector, hardware micro-ops did following:
52 	;   1. SP auto-switched to kernel mode stack
53 	;   2. STATUS32.Z flag set if in U mode at time of interrupt (U:1,K:0)
54 	;   3. Auto save: (mandatory) Push PC and STAT32 on stack
55 	;                 hardware does even if CONFIG_ARC_IRQ_NO_AUTOSAVE
56 	;  4a. Auto save: (optional) r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI
57 	;
58 	; Now
59 	;  4b. If Auto-save (optional) not enabled in hw, manually save them
60 	;   5. Manually save: r12,r30, sp,fp,gp, ACCL pair
61 	;
62 	; At the end, SP points to pt_regs
63 
64 #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
65 	; carve pt_regs on stack (case #3), PC/STAT32 already on stack
66 	sub	sp, sp, SZ_PT_REGS - 8
67 
68 	__SAVE_REGFILE_HARD
69 #else
70 	; carve pt_regs on stack (case #4), which grew partially already
71 	sub	sp, sp, PT_r0
72 #endif
73 
74 	__SAVE_REGFILE_SOFT
75 .endm
76 
77 /*------------------------------------------------------------------------*/
78 .macro EXCEPTION_PROLOGUE_KEEP_AE
79 
80 	; Before jumping to Exception Vector, hardware micro-ops did following:
81 	;   1. SP auto-switched to kernel mode stack
82 	;   2. STATUS32.Z flag set if in U mode at time of exception (U:1,K:0)
83 	;
84 	; Now manually save rest of reg file
85 	; At the end, SP points to pt_regs
86 
87 	sub	sp, sp, SZ_PT_REGS	; carve space for pt_regs
88 
89 	; _HARD saves r10 clobbered by _SOFT as scratch hence comes first
90 
91 	__SAVE_REGFILE_HARD
92 	__SAVE_REGFILE_SOFT
93 
94 	st	r0, [sp]	; orig_r0
95 
96 	lr	r10, [eret]
97 	lr	r11, [erstatus]
98 	ST2	r10, r11, PT_ret
99 
100 	lr	r10, [ecr]
101 	lr	r11, [erbta]
102 	ST2	r10, r11, PT_event
103 
104 	; OUTPUT: r10 has ECR expected by EV_Trap
105 .endm
106 
107 .macro EXCEPTION_PROLOGUE
108 
109 	EXCEPTION_PROLOGUE_KEEP_AE	; return ECR in r10
110 
111 	lr  r0, [efa]
112 	mov r1, sp
113 
114 	FAKE_RET_FROM_EXCPN		; clobbers r9
115 .endm
116 
117 /*------------------------------------------------------------------------
118  * This macro saves the registers manually which would normally be autosaved
119  * by hardware on taken interrupts. It is used by
120  *   - exception handlers (which don't have autosave)
121  *   - interrupt autosave disabled due to CONFIG_ARC_IRQ_NO_AUTOSAVE
122  */
123 .macro __SAVE_REGFILE_HARD
124 
125 	ST2	r0,  r1,  PT_r0
126 	ST2	r2,  r3,  PT_r2
127 	ST2	r4,  r5,  PT_r4
128 	ST2	r6,  r7,  PT_r6
129 	ST2	r8,  r9,  PT_r8
130 	ST2	r10, r11, PT_r10
131 
132 	st	blink, [sp, PT_blink]
133 
134 	lr	r10, [lp_end]
135 	lr	r11, [lp_start]
136 	ST2	r10, r11, PT_lpe
137 
138 	st	lp_count, [sp, PT_lpc]
139 
140 	; skip JLI, LDI, EI for now
141 .endm
142 
143 /*------------------------------------------------------------------------
144  * This macros saves a bunch of other registers which can't be autosaved for
145  * various reasons:
146  *   - r12: the last caller saved scratch reg since hardware saves in pairs so r0-r11
147  *   - r30: free reg, used by gcc as scratch
148  *   - ACCL/ACCH pair when they exist
149  */
150 .macro __SAVE_REGFILE_SOFT
151 
152 	st	fp,  [sp, PT_fp]	; r27
153 	st	r30, [sp, PT_r30]
154 	st	r12, [sp, PT_r12]
155 	st	r26, [sp, PT_r26]	; gp
156 
157 	; Saving pt_regs->sp correctly requires some extra work due to the way
158 	; Auto stack switch works
159 	;  - U mode: retrieve it from AUX_USER_SP
160 	;  - K mode: add the offset from current SP where H/w starts auto push
161 	;
162 	; 1. Utilize the fact that Z bit is set if Intr taken in U mode
163 	; 2. Upon entry SP is always saved (for any inspection, unwinding etc),
164 	;    but on return, restored only if U mode
165 
166 	lr	r10, [AUX_USER_SP]	; U mode SP
167 
168 	; ISA requires ADD.nz to have same dest and src reg operands
169 	mov.nz	r10, sp
170 	add2.nz	r10, r10, SZ_PT_REGS/4	; K mode SP
171 
172 	st	r10, [sp, PT_sp]	; SP (pt_regs->sp)
173 
174 #ifdef CONFIG_ARC_HAS_ACCL_REGS
175 	ST2	r58, r59, PT_r58
176 #endif
177 
178 	/* clobbers r10, r11 registers pair */
179 	DSP_SAVE_REGFILE_IRQ
180 
181 #ifdef CONFIG_ARC_CURR_IN_REG
182 	GET_CURR_TASK_ON_CPU	gp
183 #endif
184 
185 .endm
186 
187 /*------------------------------------------------------------------------*/
188 .macro __RESTORE_REGFILE_SOFT
189 
190 	ld	fp,  [sp, PT_fp]
191 	ld	r30, [sp, PT_r30]
192 	ld	r12, [sp, PT_r12]
193 	ld	r26, [sp, PT_r26]
194 
195 	; Restore SP (into AUX_USER_SP) only if returning to U mode
196 	;  - for K mode, it will be implicitly restored as stack is unwound
197 	;  - Z flag set on K is inverse of what hardware does on interrupt entry
198 	;    but that doesn't really matter
199 	bz	1f
200 
201 	ld	r10, [sp, PT_sp]	; SP (pt_regs->sp)
202 	sr	r10, [AUX_USER_SP]
203 1:
204 
205 	/* clobbers r10, r11 registers pair */
206 	DSP_RESTORE_REGFILE_IRQ
207 
208 #ifdef CONFIG_ARC_HAS_ACCL_REGS
209 	LD2	r58, r59, PT_r58
210 #endif
211 .endm
212 
213 /*------------------------------------------------------------------------*/
214 .macro __RESTORE_REGFILE_HARD
215 
216 	ld	blink, [sp, PT_blink]
217 
218 	LD2	r10, r11, PT_lpe
219 	sr	r10, [lp_end]
220 	sr	r11, [lp_start]
221 
222 	ld	r10, [sp, PT_lpc]	; lp_count can't be target of LD
223 	mov	lp_count, r10
224 
225 	LD2	r0,  r1,  PT_r0
226 	LD2	r2,  r3,  PT_r2
227 	LD2	r4,  r5,  PT_r4
228 	LD2	r6,  r7,  PT_r6
229 	LD2	r8,  r9,  PT_r8
230 	LD2	r10, r11, PT_r10
231 .endm
232 
233 
234 /*------------------------------------------------------------------------*/
235 .macro INTERRUPT_EPILOGUE
236 
237 	; INPUT: r0 has STAT32 of calling context
238 	; INPUT: Z flag set if returning to K mode
239 
240 	; _SOFT clobbers r10 restored by _HARD hence the order
241 
242 	__RESTORE_REGFILE_SOFT
243 
244 #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
245 	__RESTORE_REGFILE_HARD
246 
247 	; SP points to PC/STAT32: hw restores them despite NO_AUTOSAVE
248 	add	sp, sp, SZ_PT_REGS - 8
249 #else
250 	add	sp, sp, PT_r0
251 #endif
252 
253 .endm
254 
255 /*------------------------------------------------------------------------*/
256 .macro EXCEPTION_EPILOGUE
257 
258 	; INPUT: r0 has STAT32 of calling context
259 
260 	btst	r0, STATUS_U_BIT	; Z flag set if K, used in restoring SP
261 
262 	ld	r10, [sp, PT_bta]
263 	sr	r10, [erbta]
264 
265 	LD2	r10, r11, PT_ret
266 	sr	r10, [eret]
267 	sr	r11, [erstatus]
268 
269 	__RESTORE_REGFILE_SOFT
270 	__RESTORE_REGFILE_HARD
271 
272 	add	sp, sp, SZ_PT_REGS
273 .endm
274 
275 .macro FAKE_RET_FROM_EXCPN
276 	lr      r9, [status32]
277 	bclr    r9, r9, STATUS_AE_BIT
278 	bset    r9, r9, STATUS_IE_BIT
279 	kflag   r9
280 .endm
281 
282 /* Get thread_info of "current" tsk */
283 .macro GET_CURR_THR_INFO_FROM_SP  reg
284 	bmskn \reg, sp, THREAD_SHIFT - 1
285 .endm
286 
287 /* Get CPU-ID of this core */
288 .macro  GET_CPU_ID  reg
289 	lr  \reg, [identity]
290 	xbfu \reg, \reg, 0xE8	/* 00111    01000 */
291 				/* M = 8-1  N = 8 */
292 .endm
293 
294 .macro SAVE_ABI_CALLEE_REGS
295 	push	r13
296 	push	r14
297 	push	r15
298 	push	r16
299 	push	r17
300 	push	r18
301 	push	r19
302 	push	r20
303 	push	r21
304 	push	r22
305 	push	r23
306 	push	r24
307 	push	r25
308 .endm
309 
310 .macro RESTORE_ABI_CALLEE_REGS
311 	pop	r25
312 	pop	r24
313 	pop	r23
314 	pop	r22
315 	pop	r21
316 	pop	r20
317 	pop	r19
318 	pop	r18
319 	pop	r17
320 	pop	r16
321 	pop	r15
322 	pop	r14
323 	pop	r13
324 .endm
325 
326 #endif
327