xref: /linux/arch/arc/include/asm/entry-arcv2.h (revision 96ac6d435100450f0565708d9b885ea2a7400e0a)
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/irqflags-arcv2.h>
8 #include <asm/thread_info.h>	/* For THREAD_SIZE */
9 
10 /*------------------------------------------------------------------------*/
11 .macro INTERRUPT_PROLOGUE	called_from
12 
13 	; Before jumping to Interrupt Vector, hardware micro-ops did following:
14 	;   1. SP auto-switched to kernel mode stack
15 	;   2. STATUS32.Z flag set to U mode at time of interrupt (U:1, K:0)
16 	;   3. Auto saved: r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI, PC, STAT32
17 	;
18 	; Now manually save: r12, sp, fp, gp, r25
19 
20 #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
21 .ifnc \called_from, exception
22 	st.as	r9, [sp, -10]	; save r9 in it's final stack slot
23 	sub	sp, sp, 12	; skip JLI, LDI, EI
24 
25 	PUSH	lp_count
26 	PUSHAX	lp_start
27 	PUSHAX	lp_end
28 	PUSH	blink
29 
30 	PUSH	r11
31 	PUSH	r10
32 
33 	sub	sp, sp, 4	; skip r9
34 
35 	PUSH	r8
36 	PUSH	r7
37 	PUSH	r6
38 	PUSH	r5
39 	PUSH	r4
40 	PUSH	r3
41 	PUSH	r2
42 	PUSH	r1
43 	PUSH	r0
44 .endif
45 #endif
46 
47 #ifdef CONFIG_ARC_HAS_ACCL_REGS
48 	PUSH	r59
49 	PUSH	r58
50 #endif
51 
52 	PUSH	r30
53 	PUSH	r12
54 
55 	; Saving pt_regs->sp correctly requires some extra work due to the way
56 	; Auto stack switch works
57 	;  - U mode: retrieve it from AUX_USER_SP
58 	;  - K mode: add the offset from current SP where H/w starts auto push
59 	;
60 	; Utilize the fact that Z bit is set if Intr taken in U mode
61 	mov.nz	r9, sp
62 	add.nz	r9, r9, SZ_PT_REGS - PT_sp - 4
63 	bnz	1f
64 
65 	lr	r9, [AUX_USER_SP]
66 1:
67 	PUSH	r9	; SP
68 
69 	PUSH	fp
70 	PUSH	gp
71 
72 #ifdef CONFIG_ARC_CURR_IN_REG
73 	PUSH	r25			; user_r25
74 	GET_CURR_TASK_ON_CPU	r25
75 #else
76 	sub	sp, sp, 4
77 #endif
78 
79 .ifnc \called_from, exception
80 	sub	sp, sp, 12	; BTA/ECR/orig_r0 placeholder per pt_regs
81 .endif
82 
83 .endm
84 
85 /*------------------------------------------------------------------------*/
86 .macro INTERRUPT_EPILOGUE	called_from
87 
88 .ifnc \called_from, exception
89 	add	sp, sp, 12	; skip BTA/ECR/orig_r0 placeholderss
90 .endif
91 
92 #ifdef CONFIG_ARC_CURR_IN_REG
93 	POP	r25
94 #else
95 	add	sp, sp, 4
96 #endif
97 
98 	POP	gp
99 	POP	fp
100 
101 	; Don't touch AUX_USER_SP if returning to K mode (Z bit set)
102 	; (Z bit set on K mode is inverse of INTERRUPT_PROLOGUE)
103 	add.z	sp, sp, 4
104 	bz	1f
105 
106 	POPAX	AUX_USER_SP
107 1:
108 	POP	r12
109 	POP	r30
110 
111 #ifdef CONFIG_ARC_HAS_ACCL_REGS
112 	POP	r58
113 	POP	r59
114 #endif
115 
116 #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
117 .ifnc \called_from, exception
118 	POP	r0
119 	POP	r1
120 	POP	r2
121 	POP	r3
122 	POP	r4
123 	POP	r5
124 	POP	r6
125 	POP	r7
126 	POP	r8
127 	POP	r9
128 	POP	r10
129 	POP	r11
130 
131 	POP	blink
132 	POPAX	lp_end
133 	POPAX	lp_start
134 
135 	POP	r9
136 	mov	lp_count, r9
137 
138 	add	sp, sp, 12	; skip JLI, LDI, EI
139 	ld.as	r9, [sp, -10]	; reload r9 which got clobbered
140 .endif
141 #endif
142 
143 .endm
144 
145 /*------------------------------------------------------------------------*/
146 .macro EXCEPTION_PROLOGUE
147 
148 	; Before jumping to Exception Vector, hardware micro-ops did following:
149 	;   1. SP auto-switched to kernel mode stack
150 	;   2. STATUS32.Z flag set to U mode at time of interrupt (U:1,K:0)
151 	;
152 	; Now manually save the complete reg file
153 
154 	PUSH	r9		; freeup a register: slot of erstatus
155 
156 	PUSHAX	eret
157 	sub	sp, sp, 12	; skip JLI, LDI, EI
158 	PUSH	lp_count
159 	PUSHAX	lp_start
160 	PUSHAX	lp_end
161 	PUSH	blink
162 
163 	PUSH	r11
164 	PUSH	r10
165 
166 	ld.as	r9,  [sp, 10]	; load stashed r9 (status32 stack slot)
167 	lr	r10, [erstatus]
168 	st.as	r10, [sp, 10]	; save status32 at it's right stack slot
169 
170 	PUSH	r9
171 	PUSH	r8
172 	PUSH	r7
173 	PUSH	r6
174 	PUSH	r5
175 	PUSH	r4
176 	PUSH	r3
177 	PUSH	r2
178 	PUSH	r1
179 	PUSH	r0
180 
181 	; -- for interrupts, regs above are auto-saved by h/w in that order --
182 	; Now do what ISR prologue does (manually save r12, sp, fp, gp, r25)
183 	;
184 	; Set Z flag if this was from U mode (expected by INTERRUPT_PROLOGUE)
185 	; Although H/w exception micro-ops do set Z flag for U mode (just like
186 	; for interrupts), it could get clobbered in case we soft land here from
187 	; a TLB Miss exception handler (tlbex.S)
188 
189 	and	r10, r10, STATUS_U_MASK
190 	xor.f	0, r10, STATUS_U_MASK
191 
192 	INTERRUPT_PROLOGUE  exception
193 
194 	PUSHAX	erbta
195 	PUSHAX	ecr		; r9 contains ECR, expected by EV_Trap
196 
197 	PUSH	r0		; orig_r0
198 .endm
199 
200 /*------------------------------------------------------------------------*/
201 .macro EXCEPTION_EPILOGUE
202 
203 	; Assumes r0 has PT_status32
204 	btst   r0, STATUS_U_BIT	; Z flag set if K, used in INTERRUPT_EPILOGUE
205 
206 	add	sp, sp, 8	; orig_r0/ECR don't need restoring
207 	POPAX	erbta
208 
209 	INTERRUPT_EPILOGUE  exception
210 
211 	POP	r0
212 	POP	r1
213 	POP	r2
214 	POP	r3
215 	POP	r4
216 	POP	r5
217 	POP	r6
218 	POP	r7
219 	POP	r8
220 	POP	r9
221 	POP	r10
222 	POP	r11
223 
224 	POP	blink
225 	POPAX	lp_end
226 	POPAX	lp_start
227 
228 	POP	r9
229 	mov	lp_count, r9
230 
231 	add	sp, sp, 12	; skip JLI, LDI, EI
232 	POPAX	eret
233 	POPAX	erstatus
234 
235 	ld.as	r9, [sp, -12]	; reload r9 which got clobbered
236 .endm
237 
238 .macro FAKE_RET_FROM_EXCPN
239 	lr      r9, [status32]
240 	bic     r9, r9, (STATUS_U_MASK|STATUS_DE_MASK|STATUS_AE_MASK)
241 	or      r9, r9, STATUS_IE_MASK
242 	kflag   r9
243 .endm
244 
245 /* Get thread_info of "current" tsk */
246 .macro GET_CURR_THR_INFO_FROM_SP  reg
247 	bmskn \reg, sp, THREAD_SHIFT - 1
248 .endm
249 
250 /* Get CPU-ID of this core */
251 .macro  GET_CPU_ID  reg
252 	lr  \reg, [identity]
253 	xbfu \reg, \reg, 0xE8	/* 00111    01000 */
254 				/* M = 8-1  N = 8 */
255 .endm
256 
257 #endif
258