FreeBSD/Linux Kernel Cross Reference
sys/arm64/arm64/trap.c
1 /*-
2 * Copyright (c) 2014 Andrew Turner
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD: releng/11.2/sys/arm64/arm64/trap.c 321343 2017-07-21 18:06:57Z kib $");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/lock.h>
35 #include <sys/mutex.h>
36 #include <sys/pioctl.h>
37 #include <sys/proc.h>
38 #include <sys/ptrace.h>
39 #include <sys/syscall.h>
40 #include <sys/sysent.h>
41 #ifdef KDB
42 #include <sys/kdb.h>
43 #endif
44
45 #include <vm/vm.h>
46 #include <vm/pmap.h>
47 #include <vm/vm_kern.h>
48 #include <vm/vm_map.h>
49 #include <vm/vm_param.h>
50 #include <vm/vm_extern.h>
51
52 #include <machine/frame.h>
53 #include <machine/pcb.h>
54 #include <machine/pcpu.h>
55
56 #ifdef KDTRACE_HOOKS
57 #include <sys/dtrace_bsd.h>
58 #endif
59
60 #ifdef VFP
61 #include <machine/vfp.h>
62 #endif
63
64 #ifdef KDB
65 #include <machine/db_machdep.h>
66 #endif
67
68 #ifdef DDB
69 #include <ddb/db_output.h>
70 #endif
71
72 extern register_t fsu_intr_fault;
73
74 /* Called from exception.S */
75 void do_el1h_sync(struct thread *, struct trapframe *);
76 void do_el0_sync(struct thread *, struct trapframe *);
77 void do_el0_error(struct trapframe *);
78 static void print_registers(struct trapframe *frame);
79
80 int (*dtrace_invop_jump_addr)(struct trapframe *);
81
82 static __inline void
83 call_trapsignal(struct thread *td, int sig, int code, void *addr)
84 {
85 ksiginfo_t ksi;
86
87 ksiginfo_init_trap(&ksi);
88 ksi.ksi_signo = sig;
89 ksi.ksi_code = code;
90 ksi.ksi_addr = addr;
91 trapsignal(td, &ksi);
92 }
93
94 int
95 cpu_fetch_syscall_args(struct thread *td)
96 {
97 struct proc *p;
98 register_t *ap;
99 struct syscall_args *sa;
100 int nap;
101
102 nap = 8;
103 p = td->td_proc;
104 ap = td->td_frame->tf_x;
105 sa = &td->td_sa;
106
107 sa->code = td->td_frame->tf_x[8];
108
109 if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
110 sa->code = *ap++;
111 nap--;
112 }
113
114 if (p->p_sysent->sv_mask)
115 sa->code &= p->p_sysent->sv_mask;
116 if (sa->code >= p->p_sysent->sv_size)
117 sa->callp = &p->p_sysent->sv_table[0];
118 else
119 sa->callp = &p->p_sysent->sv_table[sa->code];
120
121 sa->narg = sa->callp->sy_narg;
122 memcpy(sa->args, ap, nap * sizeof(register_t));
123 if (sa->narg > nap)
124 panic("ARM64TODO: Could we have more than 8 args?");
125
126 td->td_retval[0] = 0;
127 td->td_retval[1] = 0;
128
129 return (0);
130 }
131
132 #include "../../kern/subr_syscall.c"
133
134 static void
135 svc_handler(struct thread *td, struct trapframe *frame)
136 {
137 int error;
138
139 if ((frame->tf_esr & ESR_ELx_ISS_MASK) == 0) {
140 error = syscallenter(td);
141 syscallret(td, error);
142 } else {
143 call_trapsignal(td, SIGILL, ILL_ILLOPN, (void *)frame->tf_elr);
144 userret(td, frame);
145 }
146 }
147
148 static void
149 data_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
150 uint64_t far, int lower)
151 {
152 struct vm_map *map;
153 struct proc *p;
154 struct pcb *pcb;
155 vm_prot_t ftype;
156 vm_offset_t va;
157 int error, sig, ucode;
158
159 /*
160 * According to the ARMv8-A rev. A.g, B2.10.5 "Load-Exclusive
161 * and Store-Exclusive instruction usage restrictions", state
162 * of the exclusive monitors after data abort exception is unknown.
163 */
164 clrex();
165
166 #ifdef KDB
167 if (kdb_active) {
168 kdb_reenter();
169 return;
170 }
171 #endif
172
173 pcb = td->td_pcb;
174
175 /*
176 * Special case for fuswintr and suswintr. These can't sleep so
177 * handle them early on in the trap handler.
178 */
179 if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) {
180 frame->tf_elr = pcb->pcb_onfault;
181 return;
182 }
183
184 p = td->td_proc;
185 if (lower)
186 map = &p->p_vmspace->vm_map;
187 else {
188 /* The top bit tells us which range to use */
189 if ((far >> 63) == 1)
190 map = kernel_map;
191 else
192 map = &p->p_vmspace->vm_map;
193 }
194
195 if (pmap_fault(map->pmap, esr, far) == KERN_SUCCESS)
196 return;
197
198 KASSERT(td->td_md.md_spinlock_count == 0,
199 ("data abort with spinlock held"));
200 if (td->td_critnest != 0 || WITNESS_CHECK(WARN_SLEEPOK |
201 WARN_GIANTOK, NULL, "Kernel page fault") != 0) {
202 print_registers(frame);
203 printf(" far: %16lx\n", far);
204 printf(" esr: %.8lx\n", esr);
205 panic("data abort in critical section or under mutex");
206 }
207
208 va = trunc_page(far);
209 ftype = ((esr >> 6) & 1) ? VM_PROT_READ | VM_PROT_WRITE : VM_PROT_READ;
210
211 /* Fault in the page. */
212 error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
213 if (error != KERN_SUCCESS) {
214 if (lower) {
215 sig = SIGSEGV;
216 if (error == KERN_PROTECTION_FAILURE)
217 ucode = SEGV_ACCERR;
218 else
219 ucode = SEGV_MAPERR;
220 call_trapsignal(td, sig, ucode, (void *)far);
221 } else {
222 if (td->td_intr_nesting_level == 0 &&
223 pcb->pcb_onfault != 0) {
224 frame->tf_x[0] = error;
225 frame->tf_elr = pcb->pcb_onfault;
226 return;
227 }
228
229 printf("Fatal data abort:\n");
230 print_registers(frame);
231 printf(" far: %16lx\n", far);
232 printf(" esr: %.8lx\n", esr);
233
234 #ifdef KDB
235 if (debugger_on_panic || kdb_active)
236 if (kdb_trap(ESR_ELx_EXCEPTION(esr), 0, frame))
237 return;
238 #endif
239 panic("vm_fault failed: %lx", frame->tf_elr);
240 }
241 }
242
243 if (lower)
244 userret(td, frame);
245 }
246
247 static void
248 print_registers(struct trapframe *frame)
249 {
250 u_int reg;
251
252 for (reg = 0; reg < 31; reg++) {
253 printf(" %sx%d: %16lx\n", (reg < 10) ? " " : "", reg,
254 frame->tf_x[reg]);
255 }
256 printf(" sp: %16lx\n", frame->tf_sp);
257 printf(" lr: %16lx\n", frame->tf_lr);
258 printf(" elr: %16lx\n", frame->tf_elr);
259 printf("spsr: %8x\n", frame->tf_spsr);
260 }
261
262 void
263 do_el1h_sync(struct thread *td, struct trapframe *frame)
264 {
265 uint32_t exception;
266 uint64_t esr, far;
267
268 /* Read the esr register to get the exception details */
269 esr = frame->tf_esr;
270 exception = ESR_ELx_EXCEPTION(esr);
271
272 #ifdef KDTRACE_HOOKS
273 if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
274 return;
275 #endif
276
277 CTR4(KTR_TRAP,
278 "do_el1_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td,
279 esr, frame->tf_elr, frame);
280
281 switch(exception) {
282 case EXCP_FP_SIMD:
283 case EXCP_TRAP_FP:
284 print_registers(frame);
285 printf(" esr: %.8lx\n", esr);
286 panic("VFP exception in the kernel");
287 case EXCP_INSN_ABORT:
288 case EXCP_DATA_ABORT:
289 far = READ_SPECIALREG(far_el1);
290 intr_enable();
291 data_abort(td, frame, esr, far, 0);
292 break;
293 case EXCP_BRK:
294 #ifdef KDTRACE_HOOKS
295 if ((esr & ESR_ELx_ISS_MASK) == 0x40d && \
296 dtrace_invop_jump_addr != 0) {
297 dtrace_invop_jump_addr(frame);
298 break;
299 }
300 #endif
301 /* FALLTHROUGH */
302 case EXCP_WATCHPT_EL1:
303 case EXCP_SOFTSTP_EL1:
304 #ifdef KDB
305 kdb_trap(exception, 0, frame);
306 #else
307 panic("No debugger in kernel.\n");
308 #endif
309 break;
310 default:
311 print_registers(frame);
312 panic("Unknown kernel exception %x esr_el1 %lx\n", exception,
313 esr);
314 }
315 }
316
317 /*
318 * The attempted execution of an instruction bit pattern that has no allocated
319 * instruction results in an exception with an unknown reason.
320 */
321 static void
322 el0_excp_unknown(struct trapframe *frame, uint64_t far)
323 {
324 struct thread *td;
325
326 td = curthread;
327 call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)far);
328 userret(td, frame);
329 }
330
331 void
332 do_el0_sync(struct thread *td, struct trapframe *frame)
333 {
334 uint32_t exception;
335 uint64_t esr, far;
336
337 /* Check we have a sane environment when entering from userland */
338 KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS,
339 ("Invalid pcpu address from userland: %p (tpidr %lx)",
340 get_pcpu(), READ_SPECIALREG(tpidr_el1)));
341
342 esr = frame->tf_esr;
343 exception = ESR_ELx_EXCEPTION(esr);
344 switch (exception) {
345 case EXCP_UNKNOWN:
346 case EXCP_INSN_ABORT_L:
347 case EXCP_DATA_ABORT_L:
348 case EXCP_DATA_ABORT:
349 far = READ_SPECIALREG(far_el1);
350 }
351 intr_enable();
352
353 CTR4(KTR_TRAP,
354 "do_el0_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td, esr,
355 frame->tf_elr, frame);
356
357 switch(exception) {
358 case EXCP_FP_SIMD:
359 case EXCP_TRAP_FP:
360 #ifdef VFP
361 vfp_restore_state();
362 #else
363 panic("VFP exception in userland");
364 #endif
365 break;
366 case EXCP_SVC:
367 svc_handler(td, frame);
368 break;
369 case EXCP_INSN_ABORT_L:
370 case EXCP_DATA_ABORT_L:
371 case EXCP_DATA_ABORT:
372 data_abort(td, frame, esr, far, 1);
373 break;
374 case EXCP_UNKNOWN:
375 el0_excp_unknown(frame, far);
376 break;
377 case EXCP_SP_ALIGN:
378 call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_sp);
379 userret(td, frame);
380 break;
381 case EXCP_PC_ALIGN:
382 call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr);
383 userret(td, frame);
384 break;
385 case EXCP_BRK:
386 call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr);
387 userret(td, frame);
388 break;
389 case EXCP_MSR:
390 call_trapsignal(td, SIGILL, ILL_PRVOPC, (void *)frame->tf_elr);
391 userret(td, frame);
392 break;
393 case EXCP_SOFTSTP_EL0:
394 td->td_frame->tf_spsr &= ~PSR_SS;
395 td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
396 WRITE_SPECIALREG(MDSCR_EL1,
397 READ_SPECIALREG(MDSCR_EL1) & ~DBG_MDSCR_SS);
398 call_trapsignal(td, SIGTRAP, TRAP_TRACE,
399 (void *)frame->tf_elr);
400 userret(td, frame);
401 break;
402 default:
403 call_trapsignal(td, SIGBUS, BUS_OBJERR, (void *)frame->tf_elr);
404 userret(td, frame);
405 break;
406 }
407 }
408
409 void
410 do_el0_error(struct trapframe *frame)
411 {
412
413 panic("ARM64TODO: do_el0_error");
414 }
415
Cache object: 66f96155afa092602369c9b4bd03f53b
|