void arm_netbsd_elf32_coredump_setup(struct lwp *l, void *arg) { #if defined(__ARMEB__) || defined(__ARM_EABI__) || defined(COMPAT_NETBSD32) Elf_Ehdr * const eh = arg; #if defined(__ARM_EABI__) || defined(COMPAT_NETBSD32) struct proc * const p = l->l_proc; #ifdef __ARM_EABI__ if (p->p_emul == &emul_netbsd) { eh->e_flags |= EF_ARM_EABI_VER5; } #elif defined(COMPAT_NETBSD32) if (p->p_emul == &emul_netbsd32) { eh->e_flags |= EF_ARM_EABI_VER5; } #endif #endif /* __ARM_EABI__ || COMPAT_NETBSD32 */ #ifdef __ARMEB__ if (CPU_IS_ARMV7_P() || (CPU_IS_ARMV6_P() && (armreg_sctrl_read() & CPU_CONTROL_BEND_ENABLE) == 0)) { eh->e_flags |= EF_ARM_BE8; } #endif #endif }
void undefinedinstruction(trapframe_t *tf) { struct lwp *l; vaddr_t fault_pc; int fault_instruction; int fault_code; int coprocessor; int user; struct undefined_handler *uh; #ifdef VERBOSE_ARM32 int s; #endif curcpu()->ci_und_ev.ev_count++; #ifdef KDTRACE_HOOKS if ((tf->tf_spsr & PSR_MODE) != PSR_USR32_MODE) { tf->tf_pc -= INSN_SIZE; if (dtrace_trapper(tf->tf_pc, tf) == 0) return; tf->tf_pc += INSN_SIZE; /* Reset for the rest code */ } #endif /* Enable interrupts if they were enabled before the exception. */ #ifdef acorn26 if ((tf->tf_r15 & R15_IRQ_DISABLE) == 0) int_on(); #else restore_interrupts(tf->tf_spsr & IF32_bits); #endif #ifndef acorn26 #ifdef THUMB_CODE if (tf->tf_spsr & PSR_T_bit) tf->tf_pc -= THUMB_INSN_SIZE; else #endif { tf->tf_pc -= INSN_SIZE; } #endif #ifdef __PROG26 fault_pc = tf->tf_r15 & R15_PC; #else fault_pc = tf->tf_pc; #endif /* Get the current lwp/proc structure or lwp0/proc0 if there is none. */ l = curlwp; #ifdef __PROG26 if ((tf->tf_r15 & R15_MODE) == R15_MODE_USR) { #else if ((tf->tf_spsr & PSR_MODE) == PSR_USR32_MODE) { #endif user = 1; LWP_CACHE_CREDS(l, l->l_proc); } else user = 0; #ifdef THUMB_CODE if (tf->tf_spsr & PSR_T_bit) { fault_instruction = read_thumb_insn(fault_pc, user); if (fault_instruction >= 0xe000) { fault_instruction = (fault_instruction << 16) | read_thumb_insn(fault_pc + 2, user); } } else #endif { /* * Make sure the program counter is correctly aligned so we * don't take an alignment fault trying to read the opcode. */ if (__predict_false((fault_pc & 3) != 0)) { ksiginfo_t ksi; /* Give the user an illegal instruction signal. */ KSI_INIT_TRAP(&ksi); ksi.ksi_signo = SIGILL; ksi.ksi_code = ILL_ILLOPC; ksi.ksi_addr = (uint32_t *)(intptr_t) fault_pc; trapsignal(l, &ksi); userret(l); return; } /* * Should use fuword() here .. but in the interests of * squeezing every bit of speed we will just use * ReadWord(). We know the instruction can be read * as was just executed so this will never fail unless * the kernel is screwed up in which case it does * not really matter does it ? */ fault_instruction = read_insn(fault_pc, user); } /* Update vmmeter statistics */ curcpu()->ci_data.cpu_ntrap++; #ifdef THUMB_CODE if ((tf->tf_spsr & PSR_T_bit) && !CPU_IS_ARMV7_P()) { coprocessor = THUMB_UNKNOWN_HANDLER; } else #endif { /* Check for coprocessor instruction */ /* * According to the datasheets you only need to look at * bit 27 of the instruction to tell the difference * between and undefined instruction and a coprocessor * instruction following an undefined instruction trap. * * ARMv5 adds undefined instructions in the NV space, * even when bit 27 is set. */ if ((fault_instruction & (1 << 27)) != 0 && (fault_instruction & 0xf0000000) != 0xf0000000) { coprocessor = (fault_instruction >> 8) & 0x0f; #ifdef THUMB_CODE } else if ((tf->tf_spsr & PSR_T_bit) && !CPU_IS_ARMV7_P()) { coprocessor = THUMB_UNKNOWN_HANDLER; #endif } else { coprocessor = CORE_UNKNOWN_HANDLER; } }
void data_abort_handler(trapframe_t *tf) { struct vm_map *map; struct lwp * const l = curlwp; struct cpu_info * const ci = curcpu(); u_int far, fsr; vm_prot_t ftype; void *onfault; vaddr_t va; int error; ksiginfo_t ksi; UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist); /* Grab FAR/FSR before enabling interrupts */ far = cpu_faultaddress(); fsr = cpu_faultstatus(); /* Update vmmeter statistics */ ci->ci_data.cpu_ntrap++; /* Re-enable interrupts if they were enabled previously */ KASSERT(!TRAP_USERMODE(tf) || (tf->tf_spsr & IF32_bits) == 0); if (__predict_true((tf->tf_spsr & IF32_bits) != IF32_bits)) restore_interrupts(tf->tf_spsr & IF32_bits); /* Get the current lwp structure */ UVMHIST_LOG(maphist, " (l=%#x, far=%#x, fsr=%#x", l, far, fsr, 0); UVMHIST_LOG(maphist, " tf=%#x, pc=%#x)", tf, tf->tf_pc, 0, 0); /* Data abort came from user mode? */ bool user = (TRAP_USERMODE(tf) != 0); if (user) LWP_CACHE_CREDS(l, l->l_proc); /* Grab the current pcb */ struct pcb * const pcb = lwp_getpcb(l); curcpu()->ci_abt_evs[fsr & FAULT_TYPE_MASK].ev_count++; /* Invoke the appropriate handler, if necessary */ if (__predict_false(data_aborts[fsr & FAULT_TYPE_MASK].func != NULL)) { #ifdef DIAGNOSTIC printf("%s: data_aborts fsr=0x%x far=0x%x\n", __func__, fsr, far); #endif if ((data_aborts[fsr & FAULT_TYPE_MASK].func)(tf, fsr, far, l, &ksi)) goto do_trapsignal; goto out; } /* * At this point, we're dealing with one of the following data aborts: * * FAULT_TRANS_S - Translation -- Section * FAULT_TRANS_P - Translation -- Page * FAULT_DOMAIN_S - Domain -- Section * FAULT_DOMAIN_P - Domain -- Page * FAULT_PERM_S - Permission -- Section * FAULT_PERM_P - Permission -- Page * * These are the main virtual memory-related faults signalled by * the MMU. */ /* fusubailout is used by [fs]uswintr to avoid page faulting */ if (__predict_false(pcb->pcb_onfault == fusubailout)) { tf->tf_r0 = EFAULT; tf->tf_pc = (intptr_t) pcb->pcb_onfault; return; } if (user) { lwp_settrapframe(l, tf); } /* * Make sure the Program Counter is sane. We could fall foul of * someone executing Thumb code, in which case the PC might not * be word-aligned. This would cause a kernel alignment fault * further down if we have to decode the current instruction. */ #ifdef THUMB_CODE /* * XXX: It would be nice to be able to support Thumb in the kernel * at some point. */ if (__predict_false(!user && (tf->tf_pc & 3) != 0)) { printf("\n%s: Misaligned Kernel-mode Program Counter\n", __func__); dab_fatal(tf, fsr, far, l, NULL); } #else if (__predict_false((tf->tf_pc & 3) != 0)) { if (user) { /* * Give the user an illegal instruction signal. */ /* Deliver a SIGILL to the process */ KSI_INIT_TRAP(&ksi); ksi.ksi_signo = SIGILL; ksi.ksi_code = ILL_ILLOPC; ksi.ksi_addr = (uint32_t *)(intptr_t) far; ksi.ksi_trap = fsr; goto do_trapsignal; } /* * The kernel never executes Thumb code. */ printf("\n%s: Misaligned Kernel-mode Program Counter\n", __func__); dab_fatal(tf, fsr, far, l, NULL); } #endif /* See if the CPU state needs to be fixed up */ switch (data_abort_fixup(tf, fsr, far, l)) { case ABORT_FIXUP_RETURN: return; case ABORT_FIXUP_FAILED: /* Deliver a SIGILL to the process */ KSI_INIT_TRAP(&ksi); ksi.ksi_signo = SIGILL; ksi.ksi_code = ILL_ILLOPC; ksi.ksi_addr = (uint32_t *)(intptr_t) far; ksi.ksi_trap = fsr; goto do_trapsignal; default: break; } va = trunc_page((vaddr_t)far); /* * It is only a kernel address space fault iff: * 1. user == 0 and * 2. pcb_onfault not set or * 3. pcb_onfault set and not LDRT/LDRBT/STRT/STRBT instruction. */ if (!user && (va >= VM_MIN_KERNEL_ADDRESS || (va < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW)) && __predict_true((pcb->pcb_onfault == NULL || (read_insn(tf->tf_pc, false) & 0x05200000) != 0x04200000))) { map = kernel_map; /* Was the fault due to the FPE/IPKDB ? */ if (__predict_false((tf->tf_spsr & PSR_MODE)==PSR_UND32_MODE)) { KSI_INIT_TRAP(&ksi); ksi.ksi_signo = SIGSEGV; ksi.ksi_code = SEGV_ACCERR; ksi.ksi_addr = (uint32_t *)(intptr_t) far; ksi.ksi_trap = fsr; /* * Force exit via userret() * This is necessary as the FPE is an extension to * userland that actually runs in a priveledged mode * but uses USR mode permissions for its accesses. */ user = true; goto do_trapsignal; } } else { map = &l->l_proc->p_vmspace->vm_map; } /* * We need to know whether the page should be mapped as R or R/W. * Before ARMv6, the MMU did not give us the info as to whether the * fault was caused by a read or a write. * * However, we know that a permission fault can only be the result of * a write to a read-only location, so we can deal with those quickly. * * Otherwise we need to disassemble the instruction responsible to * determine if it was a write. */ if (CPU_IS_ARMV6_P() || CPU_IS_ARMV7_P()) { ftype = (fsr & FAULT_WRITE) ? VM_PROT_WRITE : VM_PROT_READ; } else if (IS_PERMISSION_FAULT(fsr)) { ftype = VM_PROT_WRITE; } else { #ifdef THUMB_CODE /* Fast track the ARM case. */ if (__predict_false(tf->tf_spsr & PSR_T_bit)) { u_int insn = read_thumb_insn(tf->tf_pc, user); u_int insn_f8 = insn & 0xf800; u_int insn_fe = insn & 0xfe00; if (insn_f8 == 0x6000 || /* STR(1) */ insn_f8 == 0x7000 || /* STRB(1) */ insn_f8 == 0x8000 || /* STRH(1) */ insn_f8 == 0x9000 || /* STR(3) */ insn_f8 == 0xc000 || /* STM */ insn_fe == 0x5000 || /* STR(2) */ insn_fe == 0x5200 || /* STRH(2) */ insn_fe == 0x5400) /* STRB(2) */ ftype = VM_PROT_WRITE; else ftype = VM_PROT_READ; } else #endif { u_int insn = read_insn(tf->tf_pc, user); if (((insn & 0x0c100000) == 0x04000000) || /* STR[B] */ ((insn & 0x0e1000b0) == 0x000000b0) || /* STR[HD]*/ ((insn & 0x0a100000) == 0x08000000) || /* STM/CDT*/ ((insn & 0x0f9000f0) == 0x01800090)) /* STREX[BDH] */ ftype = VM_PROT_WRITE; else if ((insn & 0x0fb00ff0) == 0x01000090)/* SWP */ ftype = VM_PROT_READ | VM_PROT_WRITE; else ftype = VM_PROT_READ; } } /* * See if the fault is as a result of ref/mod emulation, * or domain mismatch. */ #ifdef DEBUG last_fault_code = fsr; #endif if (pmap_fault_fixup(map->pmap, va, ftype, user)) { UVMHIST_LOG(maphist, " <- ref/mod emul", 0, 0, 0, 0); goto out; } if (__predict_false(curcpu()->ci_intr_depth > 0)) { if (pcb->pcb_onfault) { tf->tf_r0 = EINVAL; tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; return; } printf("\nNon-emulated page fault with intr_depth > 0\n"); dab_fatal(tf, fsr, far, l, NULL); } onfault = pcb->pcb_onfault; pcb->pcb_onfault = NULL; error = uvm_fault(map, va, ftype); pcb->pcb_onfault = onfault; if (__predict_true(error == 0)) { if (user) uvm_grow(l->l_proc, va); /* Record any stack growth */ else ucas_ras_check(tf); UVMHIST_LOG(maphist, " <- uvm", 0, 0, 0, 0); goto out; } if (user == 0) { if (pcb->pcb_onfault) { tf->tf_r0 = error; tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; return; } printf("\nuvm_fault(%p, %lx, %x) -> %x\n", map, va, ftype, error); dab_fatal(tf, fsr, far, l, NULL); } KSI_INIT_TRAP(&ksi); if (error == ENOMEM) { printf("UVM: pid %d (%s), uid %d killed: " "out of swap\n", l->l_proc->p_pid, l->l_proc->p_comm, l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1); ksi.ksi_signo = SIGKILL; } else ksi.ksi_signo = SIGSEGV; ksi.ksi_code = (error == EACCES) ? SEGV_ACCERR : SEGV_MAPERR; ksi.ksi_addr = (uint32_t *)(intptr_t) far; ksi.ksi_trap = fsr; UVMHIST_LOG(maphist, " <- error (%d)", error, 0, 0, 0); do_trapsignal: call_trapsignal(l, tf, &ksi); out: /* If returning to user mode, make sure to invoke userret() */ if (user) userret(l); }
int arm_netbsd_elf32_probe(struct lwp *l, struct exec_package *epp, void *eh0, char *itp, vaddr_t *start_p) { const char *itp_suffix = NULL; const Elf_Ehdr * const eh = eh0; const bool elf_aapcs_p = (eh->e_flags & EF_ARM_EABIMASK) >= EF_ARM_EABI_VER4; #ifdef COMPAT_NETBSD32 const bool netbsd32_p = (epp->ep_esch->es_emul == &emul_netbsd32); #else const bool netbsd32_p = false; #endif #ifdef __ARM_EABI__ const bool aapcs_p = true; #else const bool aapcs_p = false; #endif #ifdef __ARMEB__ const bool be8_p = (eh->e_flags & EF_ARM_BE8) != 0; /* * If the BE-8 model is supported, CPSR[7] will be clear. * If the BE-32 model is supported, CPSR[7] will be set. */ register_t ctl = armreg_sctlr_read(); if (((ctl & CPU_CONTROL_BEND_ENABLE) != 0) == be8_p) return ENOEXEC; #endif /* __ARMEB__ */ /* * This is subtle. If we are netbsd32, then we don't want to match the * same ABI as the kernel. If we aren't (netbsd32 == false), then we * don't want to be different from the kernel's ABI. * true true true ENOEXEC * true false true 0 * true true false 0 * true false false ENOEXEC * false true true 0 * false false true ENOEXEC * false true false ENOEXEC * false false false 0 */ if (netbsd32_p ^ elf_aapcs_p ^ aapcs_p) return ENOEXEC; if (netbsd32_p) itp_suffix = (elf_aapcs_p) ? "eabi" : "oabi"; if (itp_suffix != NULL) (void)compat_elf_check_interp(epp, itp, itp_suffix); /* * Copy (if any) the machine_arch of the executable to the proc. */ if (epp->ep_machine_arch[0] != 0) { strlcpy(l->l_proc->p_md.md_march, epp->ep_machine_arch, sizeof(l->l_proc->p_md.md_march)); } /* * If we are AAPCS (EABI) and armv6/armv7, we want alignment faults * to be off. */ if (aapcs_p && (CPU_IS_ARMV7_P() || CPU_IS_ARMV6_P())) { l->l_md.md_flags |= MDLWP_NOALIGNFLT; } else { l->l_md.md_flags &= ~MDLWP_NOALIGNFLT; } return 0; }
sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READONLY, CTLTYPE_INT, "simdex_present", NULL, NULL, 0, &cpu_simdex_present, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READONLY, CTLTYPE_INT, "synchprim_present", NULL, NULL, 0, &cpu_synchprim_present, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "printfataltraps", NULL, NULL, 0, &cpu_printfataltraps, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL); cpu_unaligned_sigbus = !CPU_IS_ARMV6_P() && !CPU_IS_ARMV7_P(); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READONLY, CTLTYPE_INT, "unaligned_sigbus", SYSCTL_DESCR("Do SIGBUS for fixed unaligned accesses"), NULL, 0, &cpu_unaligned_sigbus, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL); /* * We need override the usual CTL_HW HW_MACHINE_ARCH so we * return the right machine_arch based on the running executable. */ sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READONLY, CTLTYPE_STRING, "machine_arch",