162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#ifndef __ASM_ARC_ENTRY_ARCV2_H
462306a36Sopenharmony_ci#define __ASM_ARC_ENTRY_ARCV2_H
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <asm/asm-offsets.h>
762306a36Sopenharmony_ci#include <asm/dsp-impl.h>
862306a36Sopenharmony_ci#include <asm/irqflags-arcv2.h>
962306a36Sopenharmony_ci#include <asm/thread_info.h>	/* For THREAD_SIZE */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * Interrupt/Exception stack layout (pt_regs) for ARCv2
1362306a36Sopenharmony_ci *   (End of struct aligned to end of page [unless nested])
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *  INTERRUPT                          EXCEPTION
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *    manual    ---------------------  manual
1862306a36Sopenharmony_ci *              |      orig_r0      |
1962306a36Sopenharmony_ci *              |      event/ECR    |
2062306a36Sopenharmony_ci *              |      bta          |
2162306a36Sopenharmony_ci *              |      gp           |
2262306a36Sopenharmony_ci *              |      fp           |
2362306a36Sopenharmony_ci *              |      sp           |
2462306a36Sopenharmony_ci *              |      r12          |
2562306a36Sopenharmony_ci *              |      r30          |
2662306a36Sopenharmony_ci *              |      r58          |
2762306a36Sopenharmony_ci *              |      r59          |
2862306a36Sopenharmony_ci *  hw autosave ---------------------
2962306a36Sopenharmony_ci *    optional  |      r0           |
3062306a36Sopenharmony_ci *              |      r1           |
3162306a36Sopenharmony_ci *              ~                   ~
3262306a36Sopenharmony_ci *              |      r9           |
3362306a36Sopenharmony_ci *              |      r10          |
3462306a36Sopenharmony_ci *              |      r11          |
3562306a36Sopenharmony_ci *              |      blink        |
3662306a36Sopenharmony_ci *              |      lpe          |
3762306a36Sopenharmony_ci *              |      lps          |
3862306a36Sopenharmony_ci *              |      lpc          |
3962306a36Sopenharmony_ci *              |      ei base      |
4062306a36Sopenharmony_ci *              |      ldi base     |
4162306a36Sopenharmony_ci *              |      jli base     |
4262306a36Sopenharmony_ci *              ---------------------
4362306a36Sopenharmony_ci *  hw autosave |       pc / eret   |
4462306a36Sopenharmony_ci *   mandatory  | stat32 / erstatus |
4562306a36Sopenharmony_ci *              ---------------------
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/*------------------------------------------------------------------------*/
4962306a36Sopenharmony_ci.macro INTERRUPT_PROLOGUE
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	; Before jumping to Interrupt Vector, hardware micro-ops did following:
5262306a36Sopenharmony_ci	;   1. SP auto-switched to kernel mode stack
5362306a36Sopenharmony_ci	;   2. STATUS32.Z flag set if in U mode at time of interrupt (U:1,K:0)
5462306a36Sopenharmony_ci	;   3. Auto save: (mandatory) Push PC and STAT32 on stack
5562306a36Sopenharmony_ci	;                 hardware does even if CONFIG_ARC_IRQ_NO_AUTOSAVE
5662306a36Sopenharmony_ci	;  4a. Auto save: (optional) r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI
5762306a36Sopenharmony_ci	;
5862306a36Sopenharmony_ci	; Now
5962306a36Sopenharmony_ci	;  4b. If Auto-save (optional) not enabled in hw, manually save them
6062306a36Sopenharmony_ci	;   5. Manually save: r12,r30, sp,fp,gp, ACCL pair
6162306a36Sopenharmony_ci	;
6262306a36Sopenharmony_ci	; At the end, SP points to pt_regs
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
6562306a36Sopenharmony_ci	; carve pt_regs on stack (case #3), PC/STAT32 already on stack
6662306a36Sopenharmony_ci	sub	sp, sp, SZ_PT_REGS - 8
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	__SAVE_REGFILE_HARD
6962306a36Sopenharmony_ci#else
7062306a36Sopenharmony_ci	; carve pt_regs on stack (case #4), which grew partially already
7162306a36Sopenharmony_ci	sub	sp, sp, PT_r0
7262306a36Sopenharmony_ci#endif
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	__SAVE_REGFILE_SOFT
7562306a36Sopenharmony_ci.endm
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/*------------------------------------------------------------------------*/
7862306a36Sopenharmony_ci.macro EXCEPTION_PROLOGUE_KEEP_AE
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	; Before jumping to Exception Vector, hardware micro-ops did following:
8162306a36Sopenharmony_ci	;   1. SP auto-switched to kernel mode stack
8262306a36Sopenharmony_ci	;   2. STATUS32.Z flag set if in U mode at time of exception (U:1,K:0)
8362306a36Sopenharmony_ci	;
8462306a36Sopenharmony_ci	; Now manually save rest of reg file
8562306a36Sopenharmony_ci	; At the end, SP points to pt_regs
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	sub	sp, sp, SZ_PT_REGS	; carve space for pt_regs
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	; _HARD saves r10 clobbered by _SOFT as scratch hence comes first
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	__SAVE_REGFILE_HARD
9262306a36Sopenharmony_ci	__SAVE_REGFILE_SOFT
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	st	r0, [sp]	; orig_r0
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	lr	r10, [eret]
9762306a36Sopenharmony_ci	lr	r11, [erstatus]
9862306a36Sopenharmony_ci	ST2	r10, r11, PT_ret
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	lr	r10, [ecr]
10162306a36Sopenharmony_ci	lr	r11, [erbta]
10262306a36Sopenharmony_ci	ST2	r10, r11, PT_event
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	; OUTPUT: r10 has ECR expected by EV_Trap
10562306a36Sopenharmony_ci.endm
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci.macro EXCEPTION_PROLOGUE
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	EXCEPTION_PROLOGUE_KEEP_AE	; return ECR in r10
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	lr  r0, [efa]
11262306a36Sopenharmony_ci	mov r1, sp
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	FAKE_RET_FROM_EXCPN		; clobbers r9
11562306a36Sopenharmony_ci.endm
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/*------------------------------------------------------------------------
11862306a36Sopenharmony_ci * This macro saves the registers manually which would normally be autosaved
11962306a36Sopenharmony_ci * by hardware on taken interrupts. It is used by
12062306a36Sopenharmony_ci *   - exception handlers (which don't have autosave)
12162306a36Sopenharmony_ci *   - interrupt autosave disabled due to CONFIG_ARC_IRQ_NO_AUTOSAVE
12262306a36Sopenharmony_ci */
12362306a36Sopenharmony_ci.macro __SAVE_REGFILE_HARD
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	ST2	r0,  r1,  PT_r0
12662306a36Sopenharmony_ci	ST2	r2,  r3,  PT_r2
12762306a36Sopenharmony_ci	ST2	r4,  r5,  PT_r4
12862306a36Sopenharmony_ci	ST2	r6,  r7,  PT_r6
12962306a36Sopenharmony_ci	ST2	r8,  r9,  PT_r8
13062306a36Sopenharmony_ci	ST2	r10, r11, PT_r10
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	st	blink, [sp, PT_blink]
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	lr	r10, [lp_end]
13562306a36Sopenharmony_ci	lr	r11, [lp_start]
13662306a36Sopenharmony_ci	ST2	r10, r11, PT_lpe
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	st	lp_count, [sp, PT_lpc]
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	; skip JLI, LDI, EI for now
14162306a36Sopenharmony_ci.endm
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci/*------------------------------------------------------------------------
14462306a36Sopenharmony_ci * This macros saves a bunch of other registers which can't be autosaved for
14562306a36Sopenharmony_ci * various reasons:
14662306a36Sopenharmony_ci *   - r12: the last caller saved scratch reg since hardware saves in pairs so r0-r11
14762306a36Sopenharmony_ci *   - r30: free reg, used by gcc as scratch
14862306a36Sopenharmony_ci *   - ACCL/ACCH pair when they exist
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_ci.macro __SAVE_REGFILE_SOFT
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	st	fp,  [sp, PT_fp]	; r27
15362306a36Sopenharmony_ci	st	r30, [sp, PT_r30]
15462306a36Sopenharmony_ci	st	r12, [sp, PT_r12]
15562306a36Sopenharmony_ci	st	r26, [sp, PT_r26]	; gp
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	; Saving pt_regs->sp correctly requires some extra work due to the way
15862306a36Sopenharmony_ci	; Auto stack switch works
15962306a36Sopenharmony_ci	;  - U mode: retrieve it from AUX_USER_SP
16062306a36Sopenharmony_ci	;  - K mode: add the offset from current SP where H/w starts auto push
16162306a36Sopenharmony_ci	;
16262306a36Sopenharmony_ci	; 1. Utilize the fact that Z bit is set if Intr taken in U mode
16362306a36Sopenharmony_ci	; 2. Upon entry SP is always saved (for any inspection, unwinding etc),
16462306a36Sopenharmony_ci	;    but on return, restored only if U mode
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	lr	r10, [AUX_USER_SP]	; U mode SP
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	; ISA requires ADD.nz to have same dest and src reg operands
16962306a36Sopenharmony_ci	mov.nz	r10, sp
17062306a36Sopenharmony_ci	add2.nz	r10, r10, SZ_PT_REGS/4	; K mode SP
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	st	r10, [sp, PT_sp]	; SP (pt_regs->sp)
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci#ifdef CONFIG_ARC_HAS_ACCL_REGS
17562306a36Sopenharmony_ci	ST2	r58, r59, PT_r58
17662306a36Sopenharmony_ci#endif
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* clobbers r10, r11 registers pair */
17962306a36Sopenharmony_ci	DSP_SAVE_REGFILE_IRQ
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#ifdef CONFIG_ARC_CURR_IN_REG
18262306a36Sopenharmony_ci	GET_CURR_TASK_ON_CPU	gp
18362306a36Sopenharmony_ci#endif
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci.endm
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/*------------------------------------------------------------------------*/
18862306a36Sopenharmony_ci.macro __RESTORE_REGFILE_SOFT
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	ld	fp,  [sp, PT_fp]
19162306a36Sopenharmony_ci	ld	r30, [sp, PT_r30]
19262306a36Sopenharmony_ci	ld	r12, [sp, PT_r12]
19362306a36Sopenharmony_ci	ld	r26, [sp, PT_r26]
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	; Restore SP (into AUX_USER_SP) only if returning to U mode
19662306a36Sopenharmony_ci	;  - for K mode, it will be implicitly restored as stack is unwound
19762306a36Sopenharmony_ci	;  - Z flag set on K is inverse of what hardware does on interrupt entry
19862306a36Sopenharmony_ci	;    but that doesn't really matter
19962306a36Sopenharmony_ci	bz	1f
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	ld	r10, [sp, PT_sp]	; SP (pt_regs->sp)
20262306a36Sopenharmony_ci	sr	r10, [AUX_USER_SP]
20362306a36Sopenharmony_ci1:
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	/* clobbers r10, r11 registers pair */
20662306a36Sopenharmony_ci	DSP_RESTORE_REGFILE_IRQ
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci#ifdef CONFIG_ARC_HAS_ACCL_REGS
20962306a36Sopenharmony_ci	LD2	r58, r59, PT_r58
21062306a36Sopenharmony_ci#endif
21162306a36Sopenharmony_ci.endm
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/*------------------------------------------------------------------------*/
21462306a36Sopenharmony_ci.macro __RESTORE_REGFILE_HARD
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	ld	blink, [sp, PT_blink]
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	LD2	r10, r11, PT_lpe
21962306a36Sopenharmony_ci	sr	r10, [lp_end]
22062306a36Sopenharmony_ci	sr	r11, [lp_start]
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	ld	r10, [sp, PT_lpc]	; lp_count can't be target of LD
22362306a36Sopenharmony_ci	mov	lp_count, r10
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	LD2	r0,  r1,  PT_r0
22662306a36Sopenharmony_ci	LD2	r2,  r3,  PT_r2
22762306a36Sopenharmony_ci	LD2	r4,  r5,  PT_r4
22862306a36Sopenharmony_ci	LD2	r6,  r7,  PT_r6
22962306a36Sopenharmony_ci	LD2	r8,  r9,  PT_r8
23062306a36Sopenharmony_ci	LD2	r10, r11, PT_r10
23162306a36Sopenharmony_ci.endm
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci/*------------------------------------------------------------------------*/
23562306a36Sopenharmony_ci.macro INTERRUPT_EPILOGUE
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	; INPUT: r0 has STAT32 of calling context
23862306a36Sopenharmony_ci	; INPUT: Z flag set if returning to K mode
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	; _SOFT clobbers r10 restored by _HARD hence the order
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	__RESTORE_REGFILE_SOFT
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci#ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
24562306a36Sopenharmony_ci	__RESTORE_REGFILE_HARD
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	; SP points to PC/STAT32: hw restores them despite NO_AUTOSAVE
24862306a36Sopenharmony_ci	add	sp, sp, SZ_PT_REGS - 8
24962306a36Sopenharmony_ci#else
25062306a36Sopenharmony_ci	add	sp, sp, PT_r0
25162306a36Sopenharmony_ci#endif
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci.endm
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/*------------------------------------------------------------------------*/
25662306a36Sopenharmony_ci.macro EXCEPTION_EPILOGUE
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	; INPUT: r0 has STAT32 of calling context
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	btst	r0, STATUS_U_BIT	; Z flag set if K, used in restoring SP
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	ld	r10, [sp, PT_bta]
26362306a36Sopenharmony_ci	sr	r10, [erbta]
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	LD2	r10, r11, PT_ret
26662306a36Sopenharmony_ci	sr	r10, [eret]
26762306a36Sopenharmony_ci	sr	r11, [erstatus]
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	__RESTORE_REGFILE_SOFT
27062306a36Sopenharmony_ci	__RESTORE_REGFILE_HARD
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	add	sp, sp, SZ_PT_REGS
27362306a36Sopenharmony_ci.endm
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci.macro FAKE_RET_FROM_EXCPN
27662306a36Sopenharmony_ci	lr      r9, [status32]
27762306a36Sopenharmony_ci	bclr    r9, r9, STATUS_AE_BIT
27862306a36Sopenharmony_ci	bset    r9, r9, STATUS_IE_BIT
27962306a36Sopenharmony_ci	kflag   r9
28062306a36Sopenharmony_ci.endm
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci/* Get thread_info of "current" tsk */
28362306a36Sopenharmony_ci.macro GET_CURR_THR_INFO_FROM_SP  reg
28462306a36Sopenharmony_ci	bmskn \reg, sp, THREAD_SHIFT - 1
28562306a36Sopenharmony_ci.endm
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci/* Get CPU-ID of this core */
28862306a36Sopenharmony_ci.macro  GET_CPU_ID  reg
28962306a36Sopenharmony_ci	lr  \reg, [identity]
29062306a36Sopenharmony_ci	xbfu \reg, \reg, 0xE8	/* 00111    01000 */
29162306a36Sopenharmony_ci				/* M = 8-1  N = 8 */
29262306a36Sopenharmony_ci.endm
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci#endif
295