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