]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
1f6ccfff VG |
2 | |
3 | #ifndef __ASM_ARC_ENTRY_ARCV2_H | |
4 | #define __ASM_ARC_ENTRY_ARCV2_H | |
5 | ||
6 | #include <asm/asm-offsets.h> | |
4827d0cf | 7 | #include <asm/dsp-impl.h> |
1f6ccfff VG |
8 | #include <asm/irqflags-arcv2.h> |
9 | #include <asm/thread_info.h> /* For THREAD_SIZE */ | |
10 | ||
45869eb0 VG |
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 | ||
1f6ccfff | 49 | /*------------------------------------------------------------------------*/ |
a4880801 VG |
50 | .macro INTERRUPT_PROLOGUE |
51 | ||
45869eb0 | 52 | ; (A) Before jumping to Interrupt Vector, hardware micro-ops did following: |
1f6ccfff | 53 | ; 1. SP auto-switched to kernel mode stack |
45869eb0 VG |
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 | |
1f6ccfff | 58 | ; |
45869eb0 | 59 | ; (B) Manually saved some regs: r12,r25,r30, sp,fp,gp, ACCL pair |
1f6ccfff | 60 | |
e494239a | 61 | #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE |
a4880801 VG |
62 | ; carve pt_regs on stack (case #3), PC/STAT32 already on stack |
63 | sub sp, sp, SZ_PT_REGS - 8 | |
e494239a | 64 | |
a4880801 VG |
65 | __SAVE_REGFILE_HARD |
66 | #else | |
67 | ; carve pt_regs on stack (case #4), which grew partially already | |
68 | sub sp, sp, PT_r0 | |
3d5e8012 VG |
69 | #endif |
70 | ||
a4880801 VG |
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 | |
a4880801 | 99 | |
68e5c6f0 | 100 | ; OUTPUT: r10 has ECR expected by EV_Trap |
a4880801 VG |
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] | |
1f6ccfff VG |
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 | ; | |
45869eb0 VG |
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 | ||
a4880801 | 152 | lr r10, [AUX_USER_SP] ; U mode SP |
ab854bfc | 153 | |
a4880801 VG |
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 | |
1f6ccfff | 157 | |
a4880801 | 158 | st r10, [sp, PT_sp] ; SP (pt_regs->sp) |
1f6ccfff VG |
159 | |
160 | #ifdef CONFIG_ARC_CURR_IN_REG | |
a4880801 | 161 | st r25, [sp, PT_user_r25] |
1f6ccfff | 162 | GET_CURR_TASK_ON_CPU r25 |
1f6ccfff VG |
163 | #endif |
164 | ||
a4880801 | 165 | #ifdef CONFIG_ARC_HAS_ACCL_REGS |
7ecc6c1d | 166 | ST2 r58, r59, PT_r58 |
a4880801 | 167 | #endif |
1f6ccfff | 168 | |
4827d0cf EP |
169 | /* clobbers r10, r11 registers pair */ |
170 | DSP_SAVE_REGFILE_IRQ | |
1f6ccfff VG |
171 | .endm |
172 | ||
173 | /*------------------------------------------------------------------------*/ | |
a4880801 | 174 | .macro __RESTORE_REGFILE_SOFT |
1f6ccfff | 175 | |
a4880801 | 176 | LD2 gp, fp, PT_r26 ; gp (r26), fp (r27) |
1f6ccfff | 177 | |
7ecc6c1d EP |
178 | ld r12, [sp, PT_r12] |
179 | ld r30, [sp, PT_r30] | |
1f6ccfff | 180 | |
45869eb0 VG |
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 | |
1f6ccfff VG |
185 | bz 1f |
186 | ||
a4880801 VG |
187 | ld r10, [sp, PT_sp] ; SP (pt_regs->sp) |
188 | sr r10, [AUX_USER_SP] | |
1f6ccfff | 189 | 1: |
1f6ccfff | 190 | |
a4880801 VG |
191 | #ifdef CONFIG_ARC_CURR_IN_REG |
192 | ld r25, [sp, PT_user_r25] | |
3d5e8012 VG |
193 | #endif |
194 | ||
7321e2ea EP |
195 | /* clobbers r10, r11 registers pair */ |
196 | DSP_RESTORE_REGFILE_IRQ | |
197 | ||
a4880801 | 198 | #ifdef CONFIG_ARC_HAS_ACCL_REGS |
7ecc6c1d | 199 | LD2 r58, r59, PT_r58 |
e494239a | 200 | #endif |
1f6ccfff VG |
201 | .endm |
202 | ||
203 | /*------------------------------------------------------------------------*/ | |
a4880801 | 204 | .macro __RESTORE_REGFILE_HARD |
1f6ccfff | 205 | |
a4880801 | 206 | ld blink, [sp, PT_blink] |
1f6ccfff | 207 | |
a4880801 VG |
208 | LD2 r10, r11, PT_lpe |
209 | sr r10, [lp_end] | |
210 | sr r11, [lp_start] | |
1f6ccfff | 211 | |
a4880801 VG |
212 | ld r10, [sp, PT_lpc] ; lp_count can't be target of LD |
213 | mov lp_count, r10 | |
1f6ccfff | 214 | |
a4880801 VG |
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 | |
1f6ccfff | 222 | |
1f6ccfff | 223 | |
a4880801 VG |
224 | /*------------------------------------------------------------------------*/ |
225 | .macro INTERRUPT_EPILOGUE | |
1f6ccfff | 226 | |
a4880801 VG |
227 | ; INPUT: r0 has STAT32 of calling context |
228 | ; INPUT: Z flag set if returning to K mode | |
1f6ccfff | 229 | |
a4880801 | 230 | ; _SOFT clobbers r10 restored by _HARD hence the order |
1f6ccfff | 231 | |
a4880801 VG |
232 | __RESTORE_REGFILE_SOFT |
233 | ||
234 | #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE | |
235 | __RESTORE_REGFILE_HARD | |
49b41356 VG |
236 | |
237 | ; SP points to PC/STAT32: hw restores them despite NO_AUTOSAVE | |
a4880801 VG |
238 | add sp, sp, SZ_PT_REGS - 8 |
239 | #else | |
240 | add sp, sp, PT_r0 | |
241 | #endif | |
1f6ccfff | 242 | |
1f6ccfff VG |
243 | .endm |
244 | ||
245 | /*------------------------------------------------------------------------*/ | |
246 | .macro EXCEPTION_EPILOGUE | |
247 | ||
45869eb0 | 248 | ; INPUT: r0 has STAT32 of calling context |
a4880801 VG |
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 | |
1f6ccfff VG |
263 | .endm |
264 | ||
265 | .macro FAKE_RET_FROM_EXCPN | |
266 | lr r9, [status32] | |
97abfd5d | 267 | bic r9, r9, STATUS_AE_MASK |
a3142792 | 268 | or r9, r9, STATUS_IE_MASK |
1f6ccfff VG |
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 |