xref: /openbsd-src/sys/arch/arm64/arm64/exception.S (revision cfe0f9e1d1efc00397d62f06e6565f0f44121cd9)
1/* $OpenBSD: exception.S,v 1.17 2024/03/12 13:32:53 kettenis Exp $ */
2/*-
3 * Copyright (c) 2014 Andrew Turner
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <machine/asm.h>
29#include <machine/armreg.h>
30
31#include "assym.h"
32
33	.text
34
35.macro	save_registers el
36.if \el == 1
37	mov	x18, sp
38	sub	sp, sp, #128
39.endif
40	sub	sp, sp, #(TF_SIZE + 16)
41	stp	x28, x29, [sp, #(TF_X + 28 * 8)]
42	stp	x26, x27, [sp, #(TF_X + 26 * 8)]
43	stp	x24, x25, [sp, #(TF_X + 24 * 8)]
44	stp	x22, x23, [sp, #(TF_X + 22 * 8)]
45	stp	x20, x21, [sp, #(TF_X + 20 * 8)]
46	stp	x18, x19, [sp, #(TF_X + 18 * 8)]
47	stp	x16, x17, [sp, #(TF_X + 16 * 8)]
48	stp	x14, x15, [sp, #(TF_X + 14 * 8)]
49	stp	x12, x13, [sp, #(TF_X + 12 * 8)]
50	stp	x10, x11, [sp, #(TF_X + 10 * 8)]
51	stp	x8,  x9,  [sp, #(TF_X + 8  * 8)]
52	stp	x6,  x7,  [sp, #(TF_X + 6  * 8)]
53	stp	x4,  x5,  [sp, #(TF_X + 4  * 8)]
54	stp	x2,  x3,  [sp, #(TF_X + 2  * 8)]
55	stp	x0,  x1,  [sp, #(TF_X + 0  * 8)]
56	mrs	x10, elr_el1
57	mrs	x11, spsr_el1
58.if \el == 0
59	mrs	x18, sp_el0
60.endif
61	stp	x10, x11, [sp, #(TF_ELR)]
62	stp	x18, lr, [sp, #(TF_SP)]
63	stp	fp, x10, [sp, #(TF_SIZE)]
64	mrs	x18, tpidr_el1
65	add	fp, sp, #(TF_SIZE)
66.endm
67
68.macro	restore_registers el
69.if \el == 1
70	msr	daifset, #3
71	/*
72	 * Disable interrupts, x18 may change in the interrupt exception
73	 * handler.  For EL0 exceptions, do_ast already did this.
74	 */
75.endif
76	ldp	x18,  lr, [sp, #(TF_SP)]
77	ldp	x10, x11, [sp, #(TF_ELR)]
78.if \el == 0
79	msr	sp_el0, x18
80.endif
81	msr	spsr_el1, x11
82	msr	elr_el1, x10
83	ldp	x0,  x1,  [sp, #(TF_X + 0  * 8)]
84	ldp	x2,  x3,  [sp, #(TF_X + 2  * 8)]
85	ldp	x4,  x5,  [sp, #(TF_X + 4  * 8)]
86	ldp	x6,  x7,  [sp, #(TF_X + 6  * 8)]
87	ldp	x8,  x9,  [sp, #(TF_X + 8  * 8)]
88	ldp	x10, x11, [sp, #(TF_X + 10 * 8)]
89	ldp	x12, x13, [sp, #(TF_X + 12 * 8)]
90	ldp	x14, x15, [sp, #(TF_X + 14 * 8)]
91	ldp	x16, x17, [sp, #(TF_X + 16 * 8)]
92.if \el == 0
93	/*
94	 * We only restore the callee saved registers when returning to
95	 * userland as they may have been updated by a system call or signal.
96	 */
97	ldp	x18, x19, [sp, #(TF_X + 18 * 8)]
98	ldp	x20, x21, [sp, #(TF_X + 20 * 8)]
99	ldp	x22, x23, [sp, #(TF_X + 22 * 8)]
100	ldp	x24, x25, [sp, #(TF_X + 24 * 8)]
101	ldp	x26, x27, [sp, #(TF_X + 26 * 8)]
102	ldp	x28, x29, [sp, #(TF_X + 28 * 8)]
103.else
104	ldr	     x29, [sp, #(TF_X + 29 * 8)]
105.endif
106.if \el == 0
107	add	sp, sp, #(TF_SIZE + 16)
108.else
109	mov	sp, x18
110	mrs	x18, tpidr_el1
111.endif
112.endm
113
114.macro	do_ast
115	/* Disable interrupts */
116	mrs	x19, daif
1171:
118	msr	daifset, #3
119
120	/* Check for astpending */
121	mrs	x18, tpidr_el1
122	ldr	x1, [x18, #CI_CURPROC]
123	cbz	x1, 2f
124	ldr	w2, [x1, #P_ASTPENDING]
125	cbz	w2, 2f
126
127	// clear astpending before enabling interrupts.
128	str	wzr, [x1, #P_ASTPENDING]
129
130	/* Restore interrupts */
131	msr	daif, x19
132
133	/* handle the ast */
134	mov	x0, sp
135	bl	ast
136	b	1b
1372:
138.endm
139
140.macro disable_ss
141	mrs	x2, mdscr_el1
142	and	x2, x2, #(~DBG_MDSCR_SS)
143	msr	mdscr_el1, x2
144.endm
145
146.macro allow_ss
147	mrs	x2, tpidr_el1
148	ldr	x2, [x2, #(CI_CURPCB)]
149	ldr	w2, [x2, #(PCB_FLAGS)]
150	tbz	w2, #1, 1f	/* PCB_SINGLESTEP bit */
151	mrs	x2, mdscr_el1
152	orr	x2, x2, #(DBG_MDSCR_SS)
153	msr	mdscr_el1, x2
1541:
155.endm
156
157	.globl handle_el1h_sync
158	.type handle_el1h_sync,@function
159handle_el1h_sync:
160	save_registers 1
161	mov	x0, sp
162	bl	do_el1h_sync
163	restore_registers 1
164	eret
165	dsb nsh
166	isb
167
168	.globl handle_el1h_irq
169	.type handle_el1h_irq,@function
170handle_el1h_irq:
171	save_registers 1
172	mov	x0, sp
173	bl	arm_cpu_irq
174	restore_registers 1
175	eret
176	dsb nsh
177	isb
178
179	.globl handle_el1h_fiq
180	.type handle_el1h_fiq,@function
181handle_el1h_fiq:
182	save_registers 1
183	mov	x0, sp
184	bl	arm_cpu_fiq
185	restore_registers 1
186	eret
187	dsb nsh
188	isb
189
190	.globl handle_el1h_error
191	.type handle_el1h_error,@function
192handle_el1h_error:
193	save_registers 1
194	mov	x0, sp
195	bl	do_el1h_error
196	brk	0xf13
197	1: b 1b
198
199.macro	return
200	msr	tpidrro_el0, x18
201	mrs	x18, tpidr_el1
202	ldr	x18, [x18, #CI_TRAMPOLINE_VECTORS]
203	msr	vbar_el1, x18
204	isb
205	b	tramp_return
206.endm
207
208	.globl handle_el0_sync
209	.type handle_el0_sync,@function
210handle_el0_sync:
211	save_registers 0
212	disable_ss
213	mov	x0, sp
214	bl	do_el0_sync
215	do_ast
216	allow_ss
217	restore_registers 0
218	return
219
220	.globl handle_el0_irq
221	.type handle_el0_irq,@function
222handle_el0_irq:
223	save_registers 0
224	disable_ss
225	mov	x0, sp
226	bl	arm_cpu_irq
227	do_ast
228	allow_ss
229	restore_registers 0
230	return
231
232	.globl handle_el0_fiq
233	.type handle_el0_fiq,@function
234handle_el0_fiq:
235	save_registers 0
236	disable_ss
237	mov	x0, sp
238	bl	arm_cpu_fiq
239	do_ast
240	allow_ss
241	restore_registers 0
242	return
243
244	.globl handle_el0_error
245	.type handle_el0_error,@function
246handle_el0_error:
247	save_registers 0
248	disable_ss
249	mov	x0, sp
250	bl	do_el0_error
251	brk	0xf23
252	1: b 1b
253
254ENTRY(syscall_return)
255	do_ast
256	restore_registers 0
257	return
258
259.macro	vempty
260	.align 7
261	brk	0xfff
262	1: b	1b
263.endm
264
265.macro	vector	name
266	.align 7
267	b	handle_\name
268.endm
269
270	.align 11
271	.globl exception_vectors
272exception_vectors:
273	vempty			/* Synchronous EL1t */
274	vempty			/* IRQ EL1t */
275	vempty			/* FIQ EL1t */
276	vempty			/* Error EL1t */
277
278	vector el1h_sync	/* Synchronous EL1h */
279	vector el1h_irq		/* IRQ EL1h */
280	vector el1h_fiq		/* FIQ EL1h */
281	vector el1h_error	/* Error EL1h */
282
283	vempty			/* Synchronous 64-bit EL0 */
284	vempty			/* IRQ 64-bit EL0 */
285	vempty			/* FIQ 64-bit EL0 */
286	vempty			/* Error 64-bit EL0 */
287
288	vempty			/* Synchronous 32-bit EL0 */
289	vempty			/* IRQ 32-bit EL0 */
290	vempty			/* FIQ 32-bit EL0 */
291	vempty			/* Error 32-bit EL0 */
292