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