/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/kernel/entry.S
 *
 * Kernel entry-points.
 */

#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/pal.h>
#include <asm/errno.h>
#include <asm/unistd.h>

	.text
	.set noat
	.cfi_sections	.debug_frame

.macro	CFI_START_OSF_FRAME	func
	.align	4
	.globl	\func
	.type	\func,@function
\func:
	.cfi_startproc simple
	.cfi_return_column 64
	.cfi_def_cfa	$sp, 48
	.cfi_rel_offset	64, 8
	.cfi_rel_offset	$gp, 16
	.cfi_rel_offset	$16, 24
	.cfi_rel_offset	$17, 32
	.cfi_rel_offset	$18, 40
.endm

.macro	CFI_END_OSF_FRAME	func
	.cfi_endproc
	.size	\func, . - \func
.endm

/*
 * This defines the normal kernel pt-regs layout.
 *
 * regs 9-15 preserved by C code
 * regs 16-18 saved by PAL-code
 * regs 29-30 saved and set up by PAL-code
 * JRP - Save regs 16-18 in a special area of the stack, so that
 * the palcode-provided values are available to the signal handler.
 */

.macro	SAVE_ALL
	subq	$sp, SP_OFF, $sp
	.cfi_adjust_cfa_offset	SP_OFF
	stq	$0, 0($sp)
	stq	$1, 8($sp)
	stq	$2, 16($sp)
	stq	$3, 24($sp)
	stq	$4, 32($sp)
	stq	$28, 144($sp)
	.cfi_rel_offset	$0, 0
	.cfi_rel_offset $1, 8
	.cfi_rel_offset	$2, 16
	.cfi_rel_offset	$3, 24
	.cfi_rel_offset	$4, 32
	.cfi_rel_offset	$28, 144
	lda	$2, alpha_mv
	stq	$5, 40($sp)
	stq	$6, 48($sp)
	stq	$7, 56($sp)
	stq	$8, 64($sp)
	stq	$19, 72($sp)
	stq	$20, 80($sp)
	stq	$21, 88($sp)
	ldq	$2, HAE_CACHE($2)
	stq	$22, 96($sp)
	stq	$23, 104($sp)
	stq	$24, 112($sp)
	stq	$25, 120($sp)
	stq	$26, 128($sp)
	stq	$27, 136($sp)
	stq	$2, 152($sp)
	stq	$16, 160($sp)
	stq	$17, 168($sp)
	stq	$18, 176($sp)
	.cfi_rel_offset	$5, 40
	.cfi_rel_offset	$6, 48
	.cfi_rel_offset	$7, 56
	.cfi_rel_offset	$8, 64
	.cfi_rel_offset $19, 72
	.cfi_rel_offset	$20, 80
	.cfi_rel_offset	$21, 88
	.cfi_rel_offset $22, 96
	.cfi_rel_offset	$23, 104
	.cfi_rel_offset	$24, 112
	.cfi_rel_offset	$25, 120
	.cfi_rel_offset	$26, 128
	.cfi_rel_offset	$27, 136
.endm

.macro	RESTORE_ALL
	lda	$19, alpha_mv
	ldq	$0, 0($sp)
	ldq	$1, 8($sp)
	ldq	$2, 16($sp)
	ldq	$3, 24($sp)
	ldq	$21, 152($sp)
	ldq	$20, HAE_CACHE($19)
	ldq	$4, 32($sp)
	ldq	$5, 40($sp)
	ldq	$6, 48($sp)
	ldq	$7, 56($sp)
	subq	$20, $21, $20
	ldq	$8, 64($sp)
	beq	$20, 99f
	ldq	$20, HAE_REG($19)
	stq	$21, HAE_CACHE($19)
	stq	$21, 0($20)
99:	ldq	$19, 72($sp)
	ldq	$20, 80($sp)
	ldq	$21, 88($sp)
	ldq	$22, 96($sp)
	ldq	$23, 104($sp)
	ldq	$24, 112($sp)
	ldq	$25, 120($sp)
	ldq	$26, 128($sp)
	ldq	$27, 136($sp)
	ldq	$28, 144($sp)
	addq	$sp, SP_OFF, $sp
	.cfi_restore	$0
	.cfi_restore	$1
	.cfi_restore	$2
	.cfi_restore	$3
	.cfi_restore	$4
	.cfi_restore	$5
	.cfi_restore	$6
	.cfi_restore	$7
	.cfi_restore	$8
	.cfi_restore	$19
	.cfi_restore	$20
	.cfi_restore	$21
	.cfi_restore	$22
	.cfi_restore	$23
	.cfi_restore	$24
	.cfi_restore	$25
	.cfi_restore	$26
	.cfi_restore	$27
	.cfi_restore	$28
	.cfi_adjust_cfa_offset	-SP_OFF
.endm

.macro	DO_SWITCH_STACK
	bsr	$1, do_switch_stack
	.cfi_adjust_cfa_offset	SWITCH_STACK_SIZE
	.cfi_rel_offset	$9, 0
	.cfi_rel_offset	$10, 8
	.cfi_rel_offset	$11, 16
	.cfi_rel_offset	$12, 24
	.cfi_rel_offset	$13, 32
	.cfi_rel_offset	$14, 40
	.cfi_rel_offset	$15, 48
.endm

.macro	UNDO_SWITCH_STACK
	bsr	$1, undo_switch_stack
	.cfi_restore	$9
	.cfi_restore	$10
	.cfi_restore	$11
	.cfi_restore	$12
	.cfi_restore	$13
	.cfi_restore	$14
	.cfi_restore	$15
	.cfi_adjust_cfa_offset	-SWITCH_STACK_SIZE
.endm

/*
 * Non-syscall kernel entry points.
 */

CFI_START_OSF_FRAME entInt
	SAVE_ALL
	lda	$8, 0x3fff
	lda	$26, ret_from_sys_call
	bic	$sp, $8, $8
	mov	$sp, $19
	jsr	$31, do_entInt
CFI_END_OSF_FRAME entInt

CFI_START_OSF_FRAME entArith
	SAVE_ALL
	lda	$8, 0x3fff
	lda	$26, ret_from_sys_call
	bic	$sp, $8, $8
	mov	$sp, $18
	jsr	$31, do_entArith
CFI_END_OSF_FRAME entArith

CFI_START_OSF_FRAME entMM
	SAVE_ALL
/* save $9 - $15 so the inline exception code can manipulate them.  */
	subq	$sp, 64, $sp
	.cfi_adjust_cfa_offset	64
	stq	$9, 0($sp)
	stq	$10, 8($sp)
	stq	$11, 16($sp)
	stq	$12, 24($sp)
	stq	$13, 32($sp)
	stq	$14, 40($sp)
	stq	$15, 48($sp)
	.cfi_rel_offset	$9, 0
	.cfi_rel_offset	$10, 8
	.cfi_rel_offset	$11, 16
	.cfi_rel_offset	$12, 24
	.cfi_rel_offset	$13, 32
	.cfi_rel_offset	$14, 40
	.cfi_rel_offset	$15, 48
	addq	$sp, 64, $19
/* handle the fault */
	lda	$8, 0x3fff
	bic	$sp, $8, $8
	jsr	$26, do_page_fault
/* reload the registers after the exception code played.  */
	ldq	$9, 0($sp)
	ldq	$10, 8($sp)
	ldq	$11, 16($sp)
	ldq	$12, 24($sp)
	ldq	$13, 32($sp)
	ldq	$14, 40($sp)
	ldq	$15, 48($sp)
	addq	$sp, 64, $sp
	.cfi_restore	$9
	.cfi_restore	$10
	.cfi_restore	$11
	.cfi_restore	$12
	.cfi_restore	$13
	.cfi_restore	$14
	.cfi_restore	$15
	.cfi_adjust_cfa_offset	-64
/* finish up the syscall as normal.  */
	br	ret_from_sys_call
CFI_END_OSF_FRAME entMM

CFI_START_OSF_FRAME entIF
	SAVE_ALL
	lda	$8, 0x3fff
	lda	$26, ret_from_sys_call
	bic	$sp, $8, $8
	mov	$sp, $17
	jsr	$31, do_entIF
CFI_END_OSF_FRAME entIF

CFI_START_OSF_FRAME entUna
	lda	$sp, -256($sp)
	.cfi_adjust_cfa_offset	256
	stq	$0, 0($sp)
	.cfi_rel_offset	$0, 0
	.cfi_remember_state
	ldq	$0, 256($sp)	/* get PS */
	stq	$1, 8($sp)
	stq	$2, 16($sp)
	stq	$3, 24($sp)
	and	$0, 8, $0		/* user mode? */
	stq	$4, 32($sp)
	bne	$0, entUnaUser	/* yup -> do user-level unaligned fault */
	stq	$5, 40($sp)
	stq	$6, 48($sp)
	stq	$7, 56($sp)
	stq	$8, 64($sp)
	stq	$9, 72($sp)
	stq	$10, 80($sp)
	stq	$11, 88($sp)
	stq	$12, 96($sp)
	stq	$13, 104($sp)
	stq	$14, 112($sp)
	stq	$15, 120($sp)
	/* 16-18 PAL-saved */
	stq	$19, 152($sp)
	stq	$20, 160($sp)
	stq	$21, 168($sp)
	stq	$22, 176($sp)
	stq	$23, 184($sp)
	stq	$24, 192($sp)
	stq	$25, 200($sp)
	stq	$26, 208($sp)
	stq	$27, 216($sp)
	stq	$28, 224($sp)
	mov	$sp, $19
	stq	$gp, 232($sp)
	.cfi_rel_offset	$1, 1*8
	.cfi_rel_offset	$2, 2*8
	.cfi_rel_offset	$3, 3*8
	.cfi_rel_offset	$4, 4*8
	.cfi_rel_offset	$5, 5*8
	.cfi_rel_offset	$6, 6*8
	.cfi_rel_offset	$7, 7*8
	.cfi_rel_offset	$8, 8*8
	.cfi_rel_offset	$9, 9*8
	.cfi_rel_offset	$10, 10*8
	.cfi_rel_offset	$11, 11*8
	.cfi_rel_offset	$12, 12*8
	.cfi_rel_offset	$13, 13*8
	.cfi_rel_offset	$14, 14*8
	.cfi_rel_offset	$15, 15*8
	.cfi_rel_offset	$19, 19*8
	.cfi_rel_offset	$20, 20*8
	.cfi_rel_offset	$21, 21*8
	.cfi_rel_offset	$22, 22*8
	.cfi_rel_offset	$23, 23*8
	.cfi_rel_offset	$24, 24*8
	.cfi_rel_offset	$25, 25*8
	.cfi_rel_offset	$26, 26*8
	.cfi_rel_offset	$27, 27*8
	.cfi_rel_offset	$28, 28*8
	.cfi_rel_offset	$29, 29*8
	lda	$8, 0x3fff
	stq	$31, 248($sp)
	bic	$sp, $8, $8
	jsr	$26, do_entUna
	ldq	$0, 0($sp)
	ldq	$1, 8($sp)
	ldq	$2, 16($sp)
	ldq	$3, 24($sp)
	ldq	$4, 32($sp)
	ldq	$5, 40($sp)
	ldq	$6, 48($sp)
	ldq	$7, 56($sp)
	ldq	$8, 64($sp)
	ldq	$9, 72($sp)
	ldq	$10, 80($sp)
	ldq	$11, 88($sp)
	ldq	$12, 96($sp)
	ldq	$13, 104($sp)
	ldq	$14, 112($sp)
	ldq	$15, 120($sp)
	/* 16-18 PAL-saved */
	ldq	$19, 152($sp)
	ldq	$20, 160($sp)
	ldq	$21, 168($sp)
	ldq	$22, 176($sp)
	ldq	$23, 184($sp)
	ldq	$24, 192($sp)
	ldq	$25, 200($sp)
	ldq	$26, 208($sp)
	ldq	$27, 216($sp)
	ldq	$28, 224($sp)
	ldq	$gp, 232($sp)
	lda	$sp, 256($sp)
	.cfi_restore	$1
	.cfi_restore	$2
	.cfi_restore	$3
	.cfi_restore	$4
	.cfi_restore	$5
	.cfi_restore	$6
	.cfi_restore	$7
	.cfi_restore	$8
	.cfi_restore	$9
	.cfi_restore	$10
	.cfi_restore	$11
	.cfi_restore	$12
	.cfi_restore	$13
	.cfi_restore	$14
	.cfi_restore	$15
	.cfi_restore	$19
	.cfi_restore	$20
	.cfi_restore	$21
	.cfi_restore	$22
	.cfi_restore	$23
	.cfi_restore	$24
	.cfi_restore	$25
	.cfi_restore	$26
	.cfi_restore	$27
	.cfi_restore	$28
	.cfi_restore	$29
	.cfi_adjust_cfa_offset	-256
	call_pal PAL_rti

	.align	4
entUnaUser:
	.cfi_restore_state
	ldq	$0, 0($sp)	/* restore original $0 */
	lda	$sp, 256($sp)	/* pop entUna's stack frame */
	.cfi_restore	$0
	.cfi_adjust_cfa_offset	-256
	SAVE_ALL		/* setup normal kernel stack */
	lda	$sp, -64($sp)
	.cfi_adjust_cfa_offset	64
	stq	$9, 0($sp)
	stq	$10, 8($sp)
	stq	$11, 16($sp)
	stq	$12, 24($sp)
	stq	$13, 32($sp)
	stq	$14, 40($sp)
	stq	$15, 48($sp)
	.cfi_rel_offset	$9, 0
	.cfi_rel_offset	$10, 8
	.cfi_rel_offset	$11, 16
	.cfi_rel_offset	$12, 24
	.cfi_rel_offset	$13, 32
	.cfi_rel_offset	$14, 40
	.cfi_rel_offset	$15, 48
	lda	$8, 0x3fff
	addq	$sp, 64, $19
	bic	$sp, $8, $8
	jsr	$26, do_entUnaUser
	ldq	$9, 0($sp)
	ldq	$10, 8($sp)
	ldq	$11, 16($sp)
	ldq	$12, 24($sp)
	ldq	$13, 32($sp)
	ldq	$14, 40($sp)
	ldq	$15, 48($sp)
	lda	$sp, 64($sp)
	.cfi_restore	$9
	.cfi_restore	$10
	.cfi_restore	$11
	.cfi_restore	$12
	.cfi_restore	$13
	.cfi_restore	$14
	.cfi_restore	$15
	.cfi_adjust_cfa_offset	-64
	br	ret_from_sys_call
CFI_END_OSF_FRAME entUna

CFI_START_OSF_FRAME entDbg
	SAVE_ALL
	lda	$8, 0x3fff
	lda	$26, ret_from_sys_call
	bic	$sp, $8, $8
	mov	$sp, $16
	jsr	$31, do_entDbg
CFI_END_OSF_FRAME entDbg
