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