1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * (C) Copyright 2013
4 * David Feng <fenghua@phytium.com.cn>
5 */
6
7#include <asm-offsets.h>
8#include <config.h>
9#include <asm/ptrace.h>
10#include <asm/macro.h>
11#include <linux/linkage.h>
12
13/*
14 * AArch64 exception vectors:
15 * We have four types of exceptions:
16 * - synchronous: traps, data aborts, undefined instructions, ...
17 * - IRQ: group 1 (normal) interrupts
18 * - FIQ: group 0 or secure interrupts
19 * - SError: fatal system errors
20 * There are entries for all four of those for different contexts:
21 * - from same exception level, when using the SP_EL0 stack pointer
22 * - from same exception level, when using the SP_ELx stack pointer
23 * - from lower exception level, when this is AArch64
24 * - from lower exception level, when this is AArch32
25 * Each of those 16 entries have space for 32 instructions, each entry must
26 * be 128 byte aligned, the whole table must be 2K aligned.
27 * The 32 instructions are not enough to save and restore all registers and
28 * to branch to the actual handler, so we split this up:
29 * Each entry saves the LR, branches to the save routine, then to the actual
30 * handler, then to the restore routine. The save and restore routines are
31 * each split in half and stuffed in the unused gap between the entries.
32 * Also as we do not run anything in a lower exception level, we just provide
33 * the first 8 entries for exceptions from the same EL.
34 */
35	.align	11
36	.globl	vectors
37vectors:
38	.align	7		/* Current EL Synchronous Thread */
39	stp	x29, x30, [sp, #-16]!
40	bl	_exception_entry
41	bl	do_bad_sync
42	b	exception_exit
43
44/*
45 * Save (most of) the GP registers to the stack frame.
46 * This is the first part of the shared routine called into from all entries.
47 */
48_exception_entry:
49	stp	x27, x28, [sp, #-16]!
50	stp	x25, x26, [sp, #-16]!
51	stp	x23, x24, [sp, #-16]!
52	stp	x21, x22, [sp, #-16]!
53	stp	x19, x20, [sp, #-16]!
54	stp	x17, x18, [sp, #-16]!
55	stp	x15, x16, [sp, #-16]!
56	stp	x13, x14, [sp, #-16]!
57	stp	x11, x12, [sp, #-16]!
58	stp	x9, x10, [sp, #-16]!
59	stp	x7, x8, [sp, #-16]!
60	stp	x5, x6, [sp, #-16]!
61	stp	x3, x4, [sp, #-16]!
62	stp	x1, x2, [sp, #-16]!
63	b	_save_el_regs			/* jump to the second part */
64
65	.align	7		/* Current EL IRQ Thread */
66	stp	x29, x30, [sp, #-16]!
67	bl	_exception_entry
68	bl	do_bad_irq
69	b	exception_exit
70
71/*
72 * Save exception specific context: ESR and ELR, for all exception levels.
73 * This is the second part of the shared routine called into from all entries.
74 */
75_save_el_regs:
76	/* Could be running at EL3/EL2/EL1 */
77	switch_el x11, 3f, 2f, 1f
783:	mrs	x1, esr_el3
79	mrs	x2, elr_el3
80	mrs	x3, spsr_el3
81	b	0f
822:	mrs	x1, esr_el2
83	mrs	x2, elr_el2
84	mrs	x3, spsr_el2
85	b	0f
861:	mrs	x1, esr_el1
87	mrs	x2, elr_el1
88	mrs	x3, spsr_el1
890:
90	stp	x1, x0, [sp, #-16]!
91	stp	x3, x2, [sp, #-16]!
92	mov	x0, sp
93	ret
94
95	.align	7		/* Current EL FIQ Thread */
96	stp	x29, x30, [sp, #-16]!
97	bl	_exception_entry
98	bl	do_bad_fiq
99				/* falling through to _exception_exit */
100/*
101 * Restore the exception return address, for all exception levels.
102 * This is the first part of the shared routine called into from all entries.
103 */
104exception_exit:
105	ldp	xzr, x2, [sp],#16
106	switch_el x11, 3f, 2f, 1f
1073:	msr	elr_el3, x2
108	b	_restore_regs
1092:	msr	elr_el2, x2
110	b	_restore_regs
1111:	msr	elr_el1, x2
112	b	_restore_regs		/* jump to the second part */
113
114	.align	7		/* Current EL Error Thread */
115	stp	x29, x30, [sp, #-16]!
116	bl	_exception_entry
117	bl	do_bad_error
118	b	exception_exit
119
120/*
121 * Restore the general purpose registers from the exception stack, then return.
122 * This is the second part of the shared routine called into from all entries.
123 */
124_restore_regs:
125	ldp	xzr, x0, [sp],#16
126	ldp	x1, x2, [sp],#16
127	ldp	x3, x4, [sp],#16
128	ldp	x5, x6, [sp],#16
129	ldp	x7, x8, [sp],#16
130	ldp	x9, x10, [sp],#16
131	ldp	x11, x12, [sp],#16
132	ldp	x13, x14, [sp],#16
133	ldp	x15, x16, [sp],#16
134	ldp	x17, x18, [sp],#16
135	ldp	x19, x20, [sp],#16
136	ldp	x21, x22, [sp],#16
137	ldp	x23, x24, [sp],#16
138	ldp	x25, x26, [sp],#16
139	ldp	x27, x28, [sp],#16
140	ldp	x29, x30, [sp],#16
141	eret
142
143	.align	7		 /* Current EL (SP_ELx) Synchronous Handler */
144	stp	x29, x30, [sp, #-16]!
145	bl	_exception_entry
146	bl	do_sync
147	b	exception_exit
148
149	.align	7		 /* Current EL (SP_ELx) IRQ Handler */
150	stp	x29, x30, [sp, #-16]!
151	bl	_exception_entry
152	bl	do_irq
153	b	exception_exit
154
155	.align	7		 /* Current EL (SP_ELx) FIQ Handler */
156	stp	x29, x30, [sp, #-16]!
157	bl	_exception_entry
158	bl	do_fiq
159	b	exception_exit
160
161	.align	7		 /* Current EL (SP_ELx) Error Handler */
162	stp	x29, x30, [sp, #-16]!
163	bl	_exception_entry
164	bl	do_error
165	b	exception_exit
166