The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm64/arm64/trap.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.