xref: /openbsd-src/sys/arch/arm64/arm64/trap.c (revision 45c4fed29a2f1f72f3230fde5772debe568dee13)
1 /* $OpenBSD: trap.c,v 1.50 2024/11/10 06:51:59 jsg 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 <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/lock.h>
32 #include <sys/mutex.h>
33 #include <sys/proc.h>
34 #include <sys/ptrace.h>
35 #include <sys/syscall.h>
36 #include <sys/signalvar.h>
37 #include <sys/user.h>
38 
39 #include <uvm/uvm_extern.h>
40 
41 #include <machine/cpu.h>
42 #include <machine/fpu.h>
43 #include <machine/frame.h>
44 #include <machine/pcb.h>
45 #include <machine/vmparam.h>
46 
47 #ifdef DDB
48 #include <ddb/db_output.h>
49 #endif
50 
51 /* Called from exception.S */
52 void do_el1h_sync(struct trapframe *);
53 void do_el0_sync(struct trapframe *);
54 void do_el0_error(struct trapframe *);
55 
56 void dumpregs(struct trapframe*);
57 
58 /* Check whether we're executing an unprivileged load/store instruction. */
59 static inline int
60 is_unpriv_ldst(uint64_t elr)
61 {
62 	uint32_t insn = *(uint32_t *)elr;
63 	return ((insn & 0x3f200c00) == 0x38000800);
64 }
65 
66 static inline int
67 accesstype(uint64_t esr, int exe)
68 {
69 	if (exe)
70 		return PROT_EXEC;
71 	return (!(esr & ISS_DATA_CM) && (esr & ISS_DATA_WnR)) ?
72 	    PROT_WRITE : PROT_READ;
73 }
74 
75 static void
76 udata_abort(struct trapframe *frame, uint64_t esr, uint64_t far, int exe)
77 {
78 	struct vm_map *map;
79 	struct proc *p;
80 	struct pcb *pcb;
81 	vm_prot_t access_type = accesstype(esr, exe);
82 	vaddr_t va;
83 	union sigval sv;
84 	int error = 0, sig, code;
85 
86 	pcb = curcpu()->ci_curpcb;
87 	p = curcpu()->ci_curproc;
88 
89 	va = trunc_page(far);
90 	if (va >= VM_MAXUSER_ADDRESS)
91 		curcpu()->ci_flush_bp();
92 
93 	switch (esr & ISS_DATA_DFSC_MASK) {
94 	case ISS_DATA_DFSC_ALIGN:
95 		sv.sival_ptr = (void *)far;
96 		trapsignal(p, SIGBUS, esr, BUS_ADRALN, sv);
97 		return;
98 	default:
99 		break;
100 	}
101 
102 	map = &p->p_vmspace->vm_map;
103 
104 	if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
105 	    "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
106 	    uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
107 		return;
108 
109 	/* Handle referenced/modified emulation */
110 	if (pmap_fault_fixup(map->pmap, va, access_type))
111 		return;
112 
113 	error = uvm_fault(map, va, 0, access_type);
114 
115 	if (error == 0) {
116 		uvm_grow(p, va);
117 		return;
118 	}
119 
120 	if (error == ENOMEM) {
121 		sig = SIGKILL;
122 		code = 0;
123 	} else if (error == EIO) {
124 		sig = SIGBUS;
125 		code = BUS_OBJERR;
126 	} else if (error == EACCES) {
127 		sig = SIGSEGV;
128 		code = SEGV_ACCERR;
129 	} else {
130 		sig = SIGSEGV;
131 		code = SEGV_MAPERR;
132 	}
133 	sv.sival_ptr = (void *)far;
134 	trapsignal(p, sig, esr, code, sv);
135 }
136 
137 static void
138 kdata_abort(struct trapframe *frame, uint64_t esr, uint64_t far, int exe)
139 {
140 	struct vm_map *map;
141 	struct proc *p;
142 	struct pcb *pcb;
143 	vm_prot_t access_type = accesstype(esr, exe);
144 	vaddr_t va;
145 	int error = 0;
146 
147 	pcb = curcpu()->ci_curpcb;
148 	p = curcpu()->ci_curproc;
149 
150 	va = trunc_page(far);
151 
152 	/* The top bit tells us which range to use */
153 	if ((far >> 63) == 1)
154 		map = kernel_map;
155 	else {
156 		/*
157 		 * Only allow user-space access using
158 		 * unprivileged load/store instructions.
159 		 */
160 		if (is_unpriv_ldst(frame->tf_elr))
161 			map = &p->p_vmspace->vm_map;
162 		else if (pcb->pcb_onfault != NULL)
163 			map = kernel_map;
164 		else {
165 			panic("attempt to access user address"
166 			      " 0x%llx from EL1", far);
167 		}
168 	}
169 
170 	/* Handle referenced/modified emulation */
171 	if (!pmap_fault_fixup(map->pmap, va, access_type)) {
172 		error = uvm_fault(map, va, 0, access_type);
173 
174 		if (error == 0 && map != kernel_map)
175 			uvm_grow(p, va);
176 	}
177 
178 	if (error != 0) {
179 		if (curcpu()->ci_idepth == 0 &&
180 		    pcb->pcb_onfault != NULL) {
181 			frame->tf_elr = (register_t)pcb->pcb_onfault;
182 			return;
183 		}
184 		panic("uvm_fault failed: %lx esr %llx far %llx",
185 		    frame->tf_elr, esr, far);
186 	}
187 }
188 
189 static int
190 emulate_msr(struct trapframe *frame, uint64_t esr)
191 {
192 	u_int rt = ISS_MSR_Rt(esr);
193 	uint64_t val;
194 
195 	/* Only emulate reads. */
196 	if ((esr & ISS_MSR_DIR) == 0)
197 		return 0;
198 
199 	/* Only emulate non-debug System register access. */
200 	if (ISS_MSR_OP0(esr) != 3 || ISS_MSR_OP1(esr) != 0 ||
201 	    ISS_MSR_CRn(esr) != 0)
202 		return 0;
203 
204 	switch (ISS_MSR_CRm(esr)) {
205 	case 0:
206 		switch (ISS_MSR_OP2(esr)) {
207 		case 0:		/* MIDR_EL1 */
208 			val = READ_SPECIALREG(midr_el1);
209 			break;
210 		case 5:		/* MPIDR_EL1 */
211 			/*
212 			 * Don't reveal the topology to userland.  But
213 			 * return a valid value; Bit 31 is RES1.
214 			 */
215 			val = 0x80000000;
216 			break;
217 		case 6:		/* REVIDR_EL1 */
218 			val = 0;
219 			break;
220 		default:
221 			return 0;
222 		}
223 		break;
224 	case 4:
225 		switch (ISS_MSR_OP2(esr)) {
226 		case 0:		/* ID_AA64PFR0_EL1 */
227 			val = cpu_id_aa64pfr0;
228 			break;
229 		case 1:		/* ID_AA64PFR1_EL1 */
230 			val = cpu_id_aa64pfr1;
231 			break;
232 		case 2:		/* ID_AA64PFR2_EL1 */
233 		case 4:		/* ID_AA64ZFR0_EL1 */
234 		case 5:		/* ID_AA64SMFR0_EL1 */
235 			val = 0;
236 			break;
237 		default:
238 			return 0;
239 		}
240 		break;
241 	case 6:
242 		switch (ISS_MSR_OP2(esr)) {
243 		case 0:	/* ID_AA64ISAR0_EL1 */
244 			val = cpu_id_aa64isar0;
245 			break;
246 		case 1: /* ID_AA64ISAR1_EL1 */
247 			val = cpu_id_aa64isar1;
248 			break;
249 		case 2: /* ID_AA64ISAR2_EL2 */
250 			val = cpu_id_aa64isar2;
251 			break;
252 		default:
253 			return 0;
254 		}
255 		break;
256 	case 7:
257 		switch (ISS_MSR_OP2(esr)) {
258 		case 0: /* ID_AA64MMFR0_EL1 */
259 		case 1: /* ID_AA64MMFR1_EL1 */
260 		case 2: /* ID_AA64MMFR2_EL1 */
261 		case 3: /* ID_AA64MMFR3_EL1 */
262 		case 4: /* ID_AA64MMFR4_EL1 */
263 			val = 0;
264 			break;
265 		default:
266 			return 0;
267 		}
268 		break;
269 	default:
270 		return 0;
271 	}
272 
273 	if (rt < 30)
274 		frame->tf_x[rt] = val;
275 	else if (rt == 30)
276 		frame->tf_lr = val;
277 	frame->tf_elr += 4;
278 
279 	return 1;
280 }
281 
282 void
283 do_el1h_sync(struct trapframe *frame)
284 {
285 	uint32_t exception;
286 	uint64_t esr, far;
287 
288 	/* Read the esr register to get the exception details */
289 	esr = READ_SPECIALREG(esr_el1);
290 	exception = ESR_ELx_EXCEPTION(esr);
291 	far = READ_SPECIALREG(far_el1);
292 
293 	intr_enable();
294 
295 	/*
296 	 * Sanity check we are in an exception er can handle. The IL bit
297 	 * is used to indicate the instruction length, except in a few
298 	 * exceptions described in the ARMv8 ARM.
299 	 *
300 	 * It is unclear in some cases if the bit is implementation defined.
301 	 * The Foundation Model and QEMU disagree on if the IL bit should
302 	 * be set when we are in a data fault from the same EL and the ISV
303 	 * bit (bit 24) is also set.
304 	 */
305 //	KASSERT((esr & ESR_ELx_IL) == ESR_ELx_IL ||
306 //	    (exception == EXCP_DATA_ABORT && ((esr & ISS_DATA_ISV) == 0)),
307 //	    ("Invalid instruction length in exception"));
308 
309 	switch(exception) {
310 	case EXCP_FP_SIMD:
311 	case EXCP_TRAP_FP:
312 		panic("FP exception in the kernel");
313 	case EXCP_BRANCH_TGT:
314 		panic("Branch target exception in the kernel");
315 	case EXCP_FPAC:
316 		panic("Faulting PAC trap in kernel");
317 	case EXCP_INSN_ABORT:
318 		kdata_abort(frame, esr, far, 1);
319 		break;
320 	case EXCP_DATA_ABORT:
321 		kdata_abort(frame, esr, far, 0);
322 		break;
323 	case EXCP_BRK:
324 	case EXCP_WATCHPT_EL1:
325 	case EXCP_SOFTSTP_EL1:
326 #ifdef DDB
327 		{
328 		/* XXX */
329 		int db_trapper (u_int, u_int, trapframe_t *, int);
330 		db_trapper(frame->tf_elr, 0/*XXX*/, frame, exception);
331 		}
332 #else
333 		panic("No debugger in kernel.");
334 #endif
335 		break;
336 	default:
337 #ifdef DDB
338 		{
339 		/* XXX */
340 		int db_trapper (u_int, u_int, trapframe_t *, int);
341 		db_trapper(frame->tf_elr, 0/*XXX*/, frame, exception);
342 		break;
343 		}
344 #endif
345 		panic("Unknown kernel exception %x esr_el1 %llx lr %lxpc %lx",
346 		    exception,
347 		    esr, frame->tf_lr, frame->tf_elr);
348 	}
349 }
350 
351 void
352 do_el0_sync(struct trapframe *frame)
353 {
354 	struct proc *p = curproc;
355 	union sigval sv;
356 	uint32_t exception;
357 	uint64_t esr, far;
358 
359 	esr = READ_SPECIALREG(esr_el1);
360 	exception = ESR_ELx_EXCEPTION(esr);
361 	far = READ_SPECIALREG(far_el1);
362 
363 	intr_enable();
364 
365 	p->p_addr->u_pcb.pcb_tf = frame;
366 	refreshcreds(p);
367 
368 	switch (exception) {
369 	case EXCP_UNKNOWN:
370 		curcpu()->ci_flush_bp();
371 		sv.sival_ptr = (void *)frame->tf_elr;
372 		trapsignal(p, SIGILL, esr, ILL_ILLOPC, sv);
373 		break;
374 	case EXCP_FP_SIMD:
375 	case EXCP_TRAP_FP:
376 		fpu_load(p);
377 		break;
378 	case EXCP_BRANCH_TGT:
379 		curcpu()->ci_flush_bp();
380 		sv.sival_ptr = (void *)frame->tf_elr;
381 		trapsignal(p, SIGILL, esr, ILL_BTCFI, sv);
382 		break;
383 	case EXCP_MSR:
384 		if (emulate_msr(frame, esr))
385 			break;
386 		/* FALLTHROUGH */
387 	case EXCP_FPAC:
388 		curcpu()->ci_flush_bp();
389 		sv.sival_ptr = (void *)frame->tf_elr;
390 		trapsignal(p, SIGILL, esr, ILL_ILLOPC, sv);
391 		break;
392 	case EXCP_SVC:
393 		svc_handler(frame);
394 		break;
395 	case EXCP_INSN_ABORT_L:
396 		udata_abort(frame, esr, far, 1);
397 		break;
398 	case EXCP_PC_ALIGN:
399 		curcpu()->ci_flush_bp();
400 		sv.sival_ptr = (void *)frame->tf_elr;
401 		trapsignal(p, SIGBUS, esr, BUS_ADRALN, sv);
402 		break;
403 	case EXCP_SP_ALIGN:
404 		curcpu()->ci_flush_bp();
405 		sv.sival_ptr = (void *)frame->tf_sp;
406 		trapsignal(p, SIGBUS, esr, BUS_ADRALN, sv);
407 		break;
408 	case EXCP_DATA_ABORT_L:
409 		udata_abort(frame, esr, far, 0);
410 		break;
411 	case EXCP_BRK:
412 		sv.sival_ptr = (void *)frame->tf_elr;
413 		trapsignal(p, SIGTRAP, esr, TRAP_BRKPT, sv);
414 		break;
415 	case EXCP_SOFTSTP_EL0:
416 		sv.sival_ptr = (void *)frame->tf_elr;
417 		trapsignal(p, SIGTRAP, esr, TRAP_TRACE, sv);
418 		break;
419 	default:
420 		// panic("Unknown userland exception %x esr_el1 %lx", exception,
421 		//    esr);
422 		// USERLAND MUST NOT PANIC MACHINE
423 		{
424 			// only here to debug !?!?
425 			printf("exception %x esr_el1 %llx\n", exception, esr);
426 			dumpregs(frame);
427 		}
428 		curcpu()->ci_flush_bp();
429 		KERNEL_LOCK();
430 		sigexit(p, SIGILL);
431 		KERNEL_UNLOCK();
432 	}
433 
434 	userret(p);
435 }
436 
437 static void
438 serror(struct trapframe *frame)
439 {
440 	struct cpu_info *ci = curcpu();
441 	uint64_t esr, far;
442 
443 	esr = READ_SPECIALREG(esr_el1);
444 	far = READ_SPECIALREG(far_el1);
445 
446 	printf("SError: %lx esr %llx far %0llx\n",
447 	    frame->tf_elr, esr, far);
448 
449 	if (ci->ci_serror)
450 		ci->ci_serror();
451 }
452 
453 void
454 do_el0_error(struct trapframe *frame)
455 {
456 	serror(frame);
457 	panic("do_el0_error");
458 }
459 
460 void
461 do_el1h_error(struct trapframe *frame)
462 {
463 	serror(frame);
464 	panic("do_el1h_error");
465 }
466 
467 void
468 dumpregs(struct trapframe *frame)
469 {
470 	int i;
471 
472 	for (i = 0; i < 30; i += 2) {
473 		printf("x%02d: 0x%016lx 0x%016lx\n",
474 		    i, frame->tf_x[i], frame->tf_x[i+1]);
475 	}
476 	printf("sp: 0x%016lx\n", frame->tf_sp);
477 	printf("lr: 0x%016lx\n", frame->tf_lr);
478 	printf("pc: 0x%016lx\n", frame->tf_elr);
479 	printf("spsr: 0x%016lx\n", frame->tf_spsr);
480 }
481