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 #endif 295