]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/trap.c
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / 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$");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/ktr.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.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 #include <machine/undefined.h>
56
57 #ifdef KDTRACE_HOOKS
58 #include <sys/dtrace_bsd.h>
59 #endif
60
61 #ifdef VFP
62 #include <machine/vfp.h>
63 #endif
64
65 #ifdef KDB
66 #include <machine/db_machdep.h>
67 #endif
68
69 #ifdef DDB
70 #include <ddb/db_output.h>
71 #endif
72
73 extern register_t fsu_intr_fault;
74
75 /* Called from exception.S */
76 void do_el1h_sync(struct thread *, struct trapframe *);
77 void do_el0_sync(struct thread *, struct trapframe *);
78 void do_el0_error(struct trapframe *);
79 void do_serror(struct trapframe *);
80 void unhandled_exception(struct trapframe *);
81
82 static void print_registers(struct trapframe *frame);
83
84 int (*dtrace_invop_jump_addr)(struct trapframe *);
85
86 typedef void (abort_handler)(struct thread *, struct trapframe *, uint64_t,
87     uint64_t, int);
88
89 static abort_handler align_abort;
90 static abort_handler data_abort;
91
92 static abort_handler *abort_handlers[] = {
93         [ISS_DATA_DFSC_TF_L0] = data_abort,
94         [ISS_DATA_DFSC_TF_L1] = data_abort,
95         [ISS_DATA_DFSC_TF_L2] = data_abort,
96         [ISS_DATA_DFSC_TF_L3] = data_abort,
97         [ISS_DATA_DFSC_AFF_L1] = data_abort,
98         [ISS_DATA_DFSC_AFF_L2] = data_abort,
99         [ISS_DATA_DFSC_AFF_L3] = data_abort,
100         [ISS_DATA_DFSC_PF_L1] = data_abort,
101         [ISS_DATA_DFSC_PF_L2] = data_abort,
102         [ISS_DATA_DFSC_PF_L3] = data_abort,
103         [ISS_DATA_DFSC_ALIGN] = align_abort,
104 };
105
106 static __inline void
107 call_trapsignal(struct thread *td, int sig, int code, void *addr, int trapno)
108 {
109         ksiginfo_t ksi;
110
111         ksiginfo_init_trap(&ksi);
112         ksi.ksi_signo = sig;
113         ksi.ksi_code = code;
114         ksi.ksi_addr = addr;
115         ksi.ksi_trapno = trapno;
116         trapsignal(td, &ksi);
117 }
118
119 int
120 cpu_fetch_syscall_args(struct thread *td)
121 {
122         struct proc *p;
123         register_t *ap;
124         struct syscall_args *sa;
125         int nap;
126
127         nap = 8;
128         p = td->td_proc;
129         ap = td->td_frame->tf_x;
130         sa = &td->td_sa;
131
132         sa->code = td->td_frame->tf_x[8];
133
134         if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
135                 sa->code = *ap++;
136                 nap--;
137         }
138
139         if (sa->code >= p->p_sysent->sv_size)
140                 sa->callp = &p->p_sysent->sv_table[0];
141         else
142                 sa->callp = &p->p_sysent->sv_table[sa->code];
143
144         sa->narg = sa->callp->sy_narg;
145         memcpy(sa->args, ap, nap * sizeof(register_t));
146         if (sa->narg > nap)
147                 panic("ARM64TODO: Could we have more than 8 args?");
148
149         td->td_retval[0] = 0;
150         td->td_retval[1] = 0;
151
152         return (0);
153 }
154
155 #include "../../kern/subr_syscall.c"
156
157 static void
158 svc_handler(struct thread *td, struct trapframe *frame)
159 {
160
161         if ((frame->tf_esr & ESR_ELx_ISS_MASK) == 0) {
162                 syscallenter(td);
163                 syscallret(td);
164         } else {
165                 call_trapsignal(td, SIGILL, ILL_ILLOPN, (void *)frame->tf_elr,
166                     ESR_ELx_EXCEPTION(frame->tf_esr));
167                 userret(td, frame);
168         }
169 }
170
171 static void
172 align_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
173     uint64_t far, int lower)
174 {
175         if (!lower) {
176                 print_registers(frame);
177                 printf(" far: %16lx\n", far);
178                 printf(" esr:         %.8lx\n", esr);
179                 panic("Misaligned access from kernel space!");
180         }
181
182         call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr,
183             ESR_ELx_EXCEPTION(frame->tf_esr));
184         userret(td, frame);
185 }
186
187 static void
188 data_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
189     uint64_t far, int lower)
190 {
191         struct vm_map *map;
192         struct proc *p;
193         struct pcb *pcb;
194         vm_prot_t ftype;
195         int error, sig, ucode;
196 #ifdef KDB
197         bool handled;
198 #endif
199
200         /*
201          * According to the ARMv8-A rev. A.g, B2.10.5 "Load-Exclusive
202          * and Store-Exclusive instruction usage restrictions", state
203          * of the exclusive monitors after data abort exception is unknown.
204          */
205         clrex();
206
207 #ifdef KDB
208         if (kdb_active) {
209                 kdb_reenter();
210                 return;
211         }
212 #endif
213
214         pcb = td->td_pcb;
215         p = td->td_proc;
216         if (lower)
217                 map = &p->p_vmspace->vm_map;
218         else {
219                 intr_enable();
220
221                 /* The top bit tells us which range to use */
222                 if (far >= VM_MAXUSER_ADDRESS) {
223                         map = kernel_map;
224                 } else {
225                         map = &p->p_vmspace->vm_map;
226                         if (map == NULL)
227                                 map = kernel_map;
228                 }
229         }
230
231         /*
232          * Try to handle translation, access flag, and permission faults.
233          * Translation faults may occur as a result of the required
234          * break-before-make sequence used when promoting or demoting
235          * superpages.  Such faults must not occur while holding the pmap lock,
236          * or pmap_fault() will recurse on that lock.
237          */
238         if ((lower || map == kernel_map || pcb->pcb_onfault != 0) &&
239             pmap_fault(map->pmap, esr, far) == KERN_SUCCESS)
240                 return;
241
242         KASSERT(td->td_md.md_spinlock_count == 0,
243             ("data abort with spinlock held"));
244         if (td->td_critnest != 0 || WITNESS_CHECK(WARN_SLEEPOK |
245             WARN_GIANTOK, NULL, "Kernel page fault") != 0) {
246                 print_registers(frame);
247                 printf(" far: %16lx\n", far);
248                 printf(" esr:         %.8lx\n", esr);
249                 panic("data abort in critical section or under mutex");
250         }
251
252         switch (ESR_ELx_EXCEPTION(esr)) {
253         case EXCP_INSN_ABORT:
254         case EXCP_INSN_ABORT_L:
255                 ftype = VM_PROT_EXECUTE;
256                 break;
257         default:
258                 ftype = (esr & ISS_DATA_WnR) == 0 ? VM_PROT_READ :
259                     VM_PROT_READ | VM_PROT_WRITE;
260                 break;
261         }
262
263         /* Fault in the page. */
264         error = vm_fault_trap(map, far, ftype, VM_FAULT_NORMAL, &sig, &ucode);
265         if (error != KERN_SUCCESS) {
266                 if (lower) {
267                         call_trapsignal(td, sig, ucode, (void *)far,
268                             ESR_ELx_EXCEPTION(esr));
269                 } else {
270                         if (td->td_intr_nesting_level == 0 &&
271                             pcb->pcb_onfault != 0) {
272                                 frame->tf_x[0] = error;
273                                 frame->tf_elr = pcb->pcb_onfault;
274                                 return;
275                         }
276
277                         printf("Fatal data abort:\n");
278                         print_registers(frame);
279                         printf(" far: %16lx\n", far);
280                         printf(" esr:         %.8lx\n", esr);
281
282 #ifdef KDB
283                         if (debugger_on_trap) {
284                                 kdb_why = KDB_WHY_TRAP;
285                                 handled = kdb_trap(ESR_ELx_EXCEPTION(esr), 0,
286                                     frame);
287                                 kdb_why = KDB_WHY_UNSET;
288                                 if (handled)
289                                         return;
290                         }
291 #endif
292                         panic("vm_fault failed: %lx", frame->tf_elr);
293                 }
294         }
295
296         if (lower)
297                 userret(td, frame);
298 }
299
300 static void
301 print_registers(struct trapframe *frame)
302 {
303         u_int reg;
304
305         for (reg = 0; reg < nitems(frame->tf_x); reg++) {
306                 printf(" %sx%d: %16lx\n", (reg < 10) ? " " : "", reg,
307                     frame->tf_x[reg]);
308         }
309         printf("  sp: %16lx\n", frame->tf_sp);
310         printf("  lr: %16lx\n", frame->tf_lr);
311         printf(" elr: %16lx\n", frame->tf_elr);
312         printf("spsr:         %8x\n", frame->tf_spsr);
313 }
314
315 void
316 do_el1h_sync(struct thread *td, struct trapframe *frame)
317 {
318         struct trapframe *oframe;
319         uint32_t exception;
320         uint64_t esr, far;
321         int dfsc;
322
323         /* Read the esr register to get the exception details */
324         esr = frame->tf_esr;
325         exception = ESR_ELx_EXCEPTION(esr);
326
327 #ifdef KDTRACE_HOOKS
328         if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
329                 return;
330 #endif
331
332         CTR4(KTR_TRAP,
333             "do_el1_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td,
334             esr, frame->tf_elr, frame);
335
336         oframe = td->td_frame;
337
338         switch (exception) {
339         case EXCP_BRK:
340         case EXCP_WATCHPT_EL1:
341         case EXCP_SOFTSTP_EL1:
342                 break;
343         default:
344                 td->td_frame = frame;
345                 break;
346         }
347
348         switch (exception) {
349         case EXCP_FP_SIMD:
350         case EXCP_TRAP_FP:
351 #ifdef VFP
352                 if ((td->td_pcb->pcb_fpflags & PCB_FP_KERN) != 0) {
353                         vfp_restore_state();
354                 } else
355 #endif
356                 {
357                         print_registers(frame);
358                         printf(" esr:         %.8lx\n", esr);
359                         panic("VFP exception in the kernel");
360                 }
361                 break;
362         case EXCP_INSN_ABORT:
363         case EXCP_DATA_ABORT:
364                 far = READ_SPECIALREG(far_el1);
365                 dfsc = esr & ISS_DATA_DFSC_MASK;
366                 if (dfsc < nitems(abort_handlers) &&
367                     abort_handlers[dfsc] != NULL) {
368                         abort_handlers[dfsc](td, frame, esr, far, 0);
369                 } else {
370                         print_registers(frame);
371                         printf(" far: %16lx\n", far);
372                         printf(" esr:         %.8lx\n", esr);
373                         panic("Unhandled EL1 %s abort: %x",
374                             exception == EXCP_INSN_ABORT ? "instruction" :
375                             "data", dfsc);
376                 }
377                 break;
378         case EXCP_BRK:
379 #ifdef KDTRACE_HOOKS
380                 if ((esr & ESR_ELx_ISS_MASK) == 0x40d && \
381                     dtrace_invop_jump_addr != 0) {
382                         dtrace_invop_jump_addr(frame);
383                         break;
384                 }
385 #endif
386 #ifdef KDB
387                 kdb_trap(exception, 0,
388                     (td->td_frame != NULL) ? td->td_frame : frame);
389 #else
390                 panic("No debugger in kernel.\n");
391 #endif
392                 frame->tf_elr += 4;
393                 break;
394         case EXCP_WATCHPT_EL1:
395         case EXCP_SOFTSTP_EL1:
396 #ifdef KDB
397                 kdb_trap(exception, 0,
398                     (td->td_frame != NULL) ? td->td_frame : frame);
399 #else
400                 panic("No debugger in kernel.\n");
401 #endif
402                 break;
403         case EXCP_UNKNOWN:
404                 if (undef_insn(1, frame))
405                         break;
406                 /* FALLTHROUGH */
407         default:
408                 print_registers(frame);
409                 printf(" far: %16lx\n", READ_SPECIALREG(far_el1));
410                 panic("Unknown kernel exception %x esr_el1 %lx\n", exception,
411                     esr);
412         }
413
414         td->td_frame = oframe;
415 }
416
417 void
418 do_el0_sync(struct thread *td, struct trapframe *frame)
419 {
420         pcpu_bp_harden bp_harden;
421         uint32_t exception;
422         uint64_t esr, far;
423         int dfsc;
424
425         /* Check we have a sane environment when entering from userland */
426         KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS,
427             ("Invalid pcpu address from userland: %p (tpidr %lx)",
428              get_pcpu(), READ_SPECIALREG(tpidr_el1)));
429
430         esr = frame->tf_esr;
431         exception = ESR_ELx_EXCEPTION(esr);
432         switch (exception) {
433         case EXCP_INSN_ABORT_L:
434                 far = READ_SPECIALREG(far_el1);
435
436                 /*
437                  * Userspace may be trying to train the branch predictor to
438                  * attack the kernel. If we are on a CPU affected by this
439                  * call the handler to clear the branch predictor state.
440                  */
441                 if (far > VM_MAXUSER_ADDRESS) {
442                         bp_harden = PCPU_GET(bp_harden);
443                         if (bp_harden != NULL)
444                                 bp_harden();
445                 }
446                 break;
447         case EXCP_UNKNOWN:
448         case EXCP_DATA_ABORT_L:
449         case EXCP_DATA_ABORT:
450                 far = READ_SPECIALREG(far_el1);
451                 break;
452         }
453         intr_enable();
454
455         CTR4(KTR_TRAP,
456             "do_el0_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td, esr,
457             frame->tf_elr, frame);
458
459         switch (exception) {
460         case EXCP_FP_SIMD:
461         case EXCP_TRAP_FP:
462 #ifdef VFP
463                 vfp_restore_state();
464 #else
465                 panic("VFP exception in userland");
466 #endif
467                 break;
468         case EXCP_SVC32:
469         case EXCP_SVC64:
470                 svc_handler(td, frame);
471                 break;
472         case EXCP_INSN_ABORT_L:
473         case EXCP_DATA_ABORT_L:
474         case EXCP_DATA_ABORT:
475                 dfsc = esr & ISS_DATA_DFSC_MASK;
476                 if (dfsc < nitems(abort_handlers) &&
477                     abort_handlers[dfsc] != NULL)
478                         abort_handlers[dfsc](td, frame, esr, far, 1);
479                 else {
480                         print_registers(frame);
481                         printf(" far: %16lx\n", far);
482                         printf(" esr:         %.8lx\n", esr);
483                         panic("Unhandled EL0 %s abort: %x",
484                             exception == EXCP_INSN_ABORT_L ? "instruction" :
485                             "data", dfsc);
486                 }
487                 break;
488         case EXCP_UNKNOWN:
489                 if (!undef_insn(0, frame))
490                         call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)far,
491                             exception);
492                 userret(td, frame);
493                 break;
494         case EXCP_SP_ALIGN:
495                 call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_sp,
496                     exception);
497                 userret(td, frame);
498                 break;
499         case EXCP_PC_ALIGN:
500                 call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr,
501                     exception);
502                 userret(td, frame);
503                 break;
504         case EXCP_BRKPT_EL0:
505         case EXCP_BRK:
506                 call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr,
507                     exception);
508                 userret(td, frame);
509                 break;
510         case EXCP_MSR:
511                 call_trapsignal(td, SIGILL, ILL_PRVOPC, (void *)frame->tf_elr,
512                     exception);
513                 userret(td, frame);
514                 break;
515         case EXCP_SOFTSTP_EL0:
516                 td->td_frame->tf_spsr &= ~PSR_SS;
517                 td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
518                 WRITE_SPECIALREG(mdscr_el1,
519                     READ_SPECIALREG(mdscr_el1) & ~DBG_MDSCR_SS);
520                 call_trapsignal(td, SIGTRAP, TRAP_TRACE,
521                     (void *)frame->tf_elr, exception);
522                 userret(td, frame);
523                 break;
524         default:
525                 call_trapsignal(td, SIGBUS, BUS_OBJERR, (void *)frame->tf_elr,
526                     exception);
527                 userret(td, frame);
528                 break;
529         }
530
531         KASSERT((td->td_pcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
532             ("Kernel VFP flags set while entering userspace"));
533         KASSERT(
534             td->td_pcb->pcb_fpusaved == &td->td_pcb->pcb_fpustate,
535             ("Kernel VFP state in use when entering userspace"));
536 }
537
538 /*
539  * TODO: We will need to handle these later when we support ARMv8.2 RAS.
540  */
541 void
542 do_serror(struct trapframe *frame)
543 {
544         uint64_t esr, far;
545
546         far = READ_SPECIALREG(far_el1);
547         esr = frame->tf_esr;
548
549         print_registers(frame);
550         printf(" far: %16lx\n", far);
551         printf(" esr:         %.8lx\n", esr);
552         panic("Unhandled System Error");
553 }
554
555 void
556 unhandled_exception(struct trapframe *frame)
557 {
558         uint64_t esr, far;
559
560         far = READ_SPECIALREG(far_el1);
561         esr = frame->tf_esr;
562
563         print_registers(frame);
564         printf(" far: %16lx\n", far);
565         printf(" esr:         %.8lx\n", esr);
566         panic("Unhandled exception");
567 }