285 lines
7.2 KiB
C
285 lines
7.2 KiB
C
/* 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
|