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