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