From 2a68b2b9b1a072399d23f9327c2136fda9cae912 Mon Sep 17 00:00:00 2001 From: thorpej Date: Sun, 24 Mar 2002 21:41:12 +0000 Subject: [PATCH] Use the generic 32-bit ARM fault.c --- sys/arch/hpcarm/conf/files.hpcarm | 3 +- sys/arch/hpcarm/hpcarm/fault.c | 638 ------------------------------ 2 files changed, 1 insertion(+), 640 deletions(-) delete mode 100644 sys/arch/hpcarm/hpcarm/fault.c diff --git a/sys/arch/hpcarm/conf/files.hpcarm b/sys/arch/hpcarm/conf/files.hpcarm index e23be91ab3c6..03d3a08df9f0 100644 --- a/sys/arch/hpcarm/conf/files.hpcarm +++ b/sys/arch/hpcarm/conf/files.hpcarm @@ -1,4 +1,4 @@ -# $NetBSD: files.hpcarm,v 1.35 2002/03/16 06:52:16 toshii Exp $ +# $NetBSD: files.hpcarm,v 1.36 2002/03/24 21:41:13 thorpej Exp $ # # First try for arm-specific configuration info # @@ -26,7 +26,6 @@ file arch/arm/arm32/conf.c # Generic MD files file arch/hpcarm/hpcarm/autoconf.c -file arch/hpcarm/hpcarm/fault.c file arch/hpcarm/hpcarm/intr.c file arch/hpcarm/hpcarm/process_machdep.c file arch/hpcarm/hpcarm/procfs_machdep.c procfs diff --git a/sys/arch/hpcarm/hpcarm/fault.c b/sys/arch/hpcarm/hpcarm/fault.c deleted file mode 100644 index e07c43857eb1..000000000000 --- a/sys/arch/hpcarm/hpcarm/fault.c +++ /dev/null @@ -1,638 +0,0 @@ -/* $NetBSD: fault.c,v 1.13 2001/11/27 01:12:55 thorpej Exp $ */ - -/* - * Copyright (c) 1994-1997 Mark Brinicombe. - * Copyright (c) 1994 Brini. - * All rights reserved. - * - * This code is derived from software written for Brini by Mark Brinicombe - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Brini. - * 4. The name of the company nor the name of the author may be used to - * endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * RiscBSD kernel project - * - * fault.c - * - * Fault handlers - * - * Created : 28/11/94 - */ - -#include "opt_ddb.h" -#include "opt_pmap_debug.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#ifdef DDB -#include -#endif - -#include - -#ifdef PMAP_DEBUG -extern int pmap_debug_level; -#endif /* PMAP_DEBUG */ - -int pmap_modified_emulation __P((pmap_t, vaddr_t)); -int pmap_handled_emulation __P((pmap_t, vaddr_t)); -pt_entry_t *pmap_pte __P((pmap_t pmap, vaddr_t va)); -int cowfault __P((vaddr_t)); - -int fetchuserword __P((u_int address, u_int *location)); -extern char fusubailout[]; - -/* Abort code */ - -/* Define text descriptions of the different aborts */ - -static const char *aborts[16] = { - "Write buffer fault", - "Alignment fault", - "Write buffer fault", - "Alignment fault", - "Bus error (LF section)", - "Translation fault (section)", - "Bus error (page)", - "Translation fault (page)", - "Bus error (section)", - "Domain error (section)", - "Bus error (page)", - "Domain error (page)", - "Bus error trans (L1)", - "Permission error (section)", - "Bus error trans (L2)", - "Permission error (page)" -}; - -void -report_abort(prefix, fault_status, fault_address, fault_pc) - const char *prefix; - u_int fault_status; - u_int fault_address; - u_int fault_pc; -{ -#ifndef DEBUG - if (prefix == NULL) { -#endif - if (prefix) - printf("%s ", prefix); - printf("Data abort: '%s' status=%03x address=%08x PC=%08x\n", - aborts[fault_status & FAULT_TYPE_MASK], - fault_status & 0xfff, fault_address, fault_pc); -#ifndef DEBUG - } -#endif -} - -/* - * void data_abort_handler(trapframe_t *frame) - * - * Abort handler called when read/write occurs at an address of - * a non existent or restricted (access permissions) memory page. - * We first need to identify the type of page fault. - */ - -#define TRAP_CODE ((fault_status & 0x0f) | (fault_address & 0xfffffff0)) - -void -data_abort_handler(frame) - trapframe_t *frame; -{ - struct proc *p; - struct pcb *pcb; - u_int fault_address; - u_int fault_status; - u_int fault_pc; - u_int fault_instruction; - int fault_code; - int user; - int error; - void *onfault; - - /* - * Must get fault address and status from the CPU before - * re-enabling interrupts. (Interrupt handlers may take - * R/M emulation faults.) - */ - fault_address = cpu_faultaddress(); - fault_status = cpu_faultstatus(); - fault_pc = frame->tf_pc; - - /* - * Enable IRQ's (disabled by CPU on abort) if trapframe - * shows they were enabled. - */ - if (!(frame->tf_spsr & I32_bit)) - enable_interrupts(I32_bit); - -#ifdef DEBUG - if ((GetCPSR() & PSR_MODE) != PSR_SVC32_MODE) - panic("data_abort_handler: not in SVC32 mode"); -#endif - - /* Update vmmeter statistics */ - uvmexp.traps++; - - /* Extract the fault code from the fault status */ - fault_code = fault_status & FAULT_TYPE_MASK; - - /* Get the current proc structure or proc0 if there is none */ - if ((p = curproc) == NULL) - p = &proc0; - - /* - * can't use curpcb, as it might be NULL; and we have p in - * a register anyway - */ - pcb = &p->p_addr->u_pcb; - - /* fusubailout is used by [fs]uswintr to avoid page faulting */ - if (pcb->pcb_onfault - && ((fault_code != FAULT_TRANS_S && fault_code != FAULT_TRANS_P && - fault_code != FAULT_PERM_S && fault_code != FAULT_PERM_P) - || pcb->pcb_onfault == fusubailout)) { - -copyfault: -#ifdef DEBUG - printf("Using pcb_onfault=%p addr=%08x st=%08x p=%p\n", - pcb->pcb_onfault, fault_address, fault_status, p); -#endif - frame->tf_pc = (u_int)pcb->pcb_onfault; - if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) - panic("Yikes pcb_onfault=%p during USR mode fault\n", - pcb->pcb_onfault); - return; - } - - /* More debug stuff */ - - fault_instruction = ReadWord(fault_pc); - -#ifdef PMAP_DEBUG - if (pmap_debug_level >= 0) { - report_abort(NULL, fault_status, fault_address, fault_pc); - printf("Instruction @V%08x = %08x\n", - fault_pc, fault_instruction); - } -#endif - - /* Call the cpu specific abort fixup routine */ - error = cpu_dataabt_fixup(frame); - if (error == ABORT_FIXUP_RETURN) - return; - if (error == ABORT_FIXUP_FAILED) { - printf("pc = 0x%08x, insn = ", fault_pc); - disassemble(fault_pc); - panic("data abort fixup failed\n"); - } - -#ifdef PMAP_DEBUG - if (pmap_debug_level >= 0) - printf("fault in process %p\n", p); -#endif - -#ifdef DEBUG - /* Is this needed ? */ - if (pcb != curpcb) { - printf("data_abort: Alert ! pcb(%p) != curpcb(%p)\n", - pcb, curpcb); - printf("data_abort: Alert ! proc(%p), curproc(%p)\n", - p, curproc); - } -#endif /* DEBUG */ - - /* Were we in user mode when the abort occurred ? */ - if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) { - /* - * Note that the fault was from USR mode. - */ - user = 1; - p->p_addr->u_pcb.pcb_tf = frame; - } else - user = 0; - - /* Now act on the fault type */ - switch (fault_code) { - case FAULT_WRTBUF_0: /* Write Buffer Fault */ - case FAULT_WRTBUF_1: /* Write Buffer Fault */ - /* If this happens forget it no point in continuing */ - - /* FALLTHROUGH */ - - case FAULT_ALIGN_0: /* Alignment Fault */ - case FAULT_ALIGN_1: /* Alignment Fault */ - /* - * Really this should just kill the process. - * Alignment faults are turned off in the kernel - * in order to get better performance from shorts with - * GCC so an alignment fault means somebody has played - * with the control register in the CPU. Might as well - * panic as the kernel was not compiled for aligned accesses. - */ - - /* FALLTHROUGH */ - - case FAULT_BUSERR_0: /* Bus Error LF Section */ - case FAULT_BUSERR_1: /* Bus Error Page */ - case FAULT_BUSERR_2: /* Bus Error Section */ - case FAULT_BUSERR_3: /* Bus Error Page */ - /* What will accutally cause a bus error ? */ - /* Real bus errors are not a process problem but hardware */ - - /* FALLTHROUGH */ - - case FAULT_DOMAIN_S: /* Section Domain Error Fault */ - case FAULT_DOMAIN_P: /* Page Domain Error Fault*/ - /* - * Right well we dont use domains, everything is - * always a client and thus subject to access permissions. - * If we get a domain error then we have corrupts PTE's - * so we might as well die ! - * I suppose eventually this should just kill the process - * who owns the PTE's but if this happens it implies a - * kernel problem. - */ - - /* FALLTHROUGH */ - - case FAULT_BUSTRNL1: /* Bus Error Trans L1 Fault */ - case FAULT_BUSTRNL2: /* Bus Error Trans L2 Fault */ - /* - * These faults imply that the PTE is corrupt. - * Likely to be a kernel fault so we had better stop. - */ - - /* FALLTHROUGH */ - - default : - /* Are there any combinations I have missed ? */ - report_abort(NULL, fault_status, fault_address, fault_pc); - - we_re_toast: - /* - * Were are dead, try and provide some debug - * information before dying. - */ -#ifdef DDB - printf("Unhandled trap (frame = %p)\n", frame); - report_abort(NULL, fault_status, fault_address, fault_pc); - kdb_trap(-1, frame); - return; -#else - panic("Unhandled trap (frame = %p)", frame); -#endif /* DDB */ - - case FAULT_TRANS_P: /* Page Translation Fault */ - case FAULT_PERM_P: /* Page Permission Fault */ - case FAULT_TRANS_S: /* Section Translation Fault */ - case FAULT_PERM_S: /* Section Permission Fault */ - /* - * Page/section translation/permission fault -- need to fault in - * the page and possibly the page table page. - */ - { - register vaddr_t va; - register struct vmspace *vm = p->p_vmspace; - register struct vm_map *map; - int rv; - vm_prot_t ftype; - extern struct vm_map *kernel_map; - - va = trunc_page((vaddr_t)fault_address); - -#ifdef PMAP_DEBUG - if (pmap_debug_level >= 0) - printf("page fault: addr=V%08lx ", va); -#endif - - /* - * It is only a kernel address space fault iff: - * 1. user == 0 and - * 2. pcb_onfault not set or - * 3. pcb_onfault set but supervisor space fault - * The last can occur during an exec() copyin where the - * argument space is lazy-allocated. - */ - if (!user && - (va >= VM_MIN_KERNEL_ADDRESS || va < VM_MIN_ADDRESS)) { - /* Was the fault due to the FPE/IPKDB ? */ - if ((frame->tf_spsr & PSR_MODE) == PSR_UND32_MODE) { - report_abort("UND32", fault_status, - fault_address, fault_pc); - trapsignal(p, SIGSEGV, TRAP_CODE); - - /* - * 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. - */ - userret(p); - return; - } - map = kernel_map; - } else - map = &vm->vm_map; - -#ifdef PMAP_DEBUG - if (pmap_debug_level >= 0) - printf("vmmap=%p ", map); -#endif - - if (map == NULL) - panic("No map for fault address\n"); - - /* - * We need to know whether the page should be mapped - * as R or R/W. The MMU does not give us the info as - * to whether the fault was caused by a read or a write. - * This means we need to disassemble the instruction - * responsible and determine if it was a read or write - * instruction. - */ - /* STR instruction ? */ - if ((fault_instruction & 0x0c100000) == 0x04000000) - ftype = VM_PROT_READ | VM_PROT_WRITE; - /* STM or CDT instruction ? */ - else if ((fault_instruction & 0x0a100000) == 0x08000000) - ftype = VM_PROT_READ | VM_PROT_WRITE; - /* STRH, STRSH or STRSB instruction ? */ - else if ((fault_instruction & 0x0e100090) == 0x00000090) - ftype = VM_PROT_READ | VM_PROT_WRITE; - /* SWP instruction ? */ - else if ((fault_instruction & 0x0fb00ff0) == 0x01000090) - ftype = VM_PROT_READ | VM_PROT_WRITE; - else - ftype = VM_PROT_READ; - -#ifdef PMAP_DEBUG - if (pmap_debug_level >= 0) - printf("fault protection = %d\n", ftype); -#endif - - if ((ftype & VM_PROT_WRITE) ? - pmap_modified_emulation(map->pmap, va) : - pmap_handled_emulation(map->pmap, va)) - goto out; - -#ifdef DIAGNOSTIC - if (current_intr_depth > 0) { -#ifdef DDB - printf("Non-emulated page fault with intr_depth > 0\n"); - report_abort(NULL, fault_status, fault_address, fault_pc); - kdb_trap(-1, frame); - return; -#else - panic("Fault with intr_depth > 0"); -#endif /* DDB */ - } -#endif /* DIAGNOSTIC */ - - onfault = pcb->pcb_onfault; - pcb->pcb_onfault = NULL; - rv = uvm_fault(map, va, 0, ftype); - pcb->pcb_onfault = onfault; - if (rv == 0) - goto out; - - if (user == 0) { - if (pcb->pcb_onfault) - goto copyfault; - printf("[u]vm_fault(%p, %lx, %x, 0) -> %x\n", - map, va, ftype, rv); - goto we_re_toast; - } - - report_abort("", fault_status, fault_address, fault_pc); - if (rv == ENOMEM) { - printf("UVM: pid %d (%s), uid %d killed: " - "out of swap\n", p->p_pid, p->p_comm, - p->p_cred && p->p_ucred ? - p->p_ucred->cr_uid : -1); - trapsignal(p, SIGKILL, TRAP_CODE); - } else - trapsignal(p, SIGSEGV, TRAP_CODE); - break; - } - } - -out: - /* Call userret() if it was a USR mode fault */ - if (user) - userret(p); -} - - -/* - * void prefetch_abort_handler(trapframe_t *frame) - * - * Abort handler called when instruction execution occurs at - * a non existent or restricted (access permissions) memory page. - * If the address is invalid and we were in SVC mode then panic as - * the kernel should never prefetch abort. - * If the address is invalid and the page is mapped then the user process - * does no have read permission so send it a signal. - * Otherwise fault the page in and try again. - */ - -extern int kernel_debug; - -void -prefetch_abort_handler(frame) - trapframe_t *frame; -{ - register u_int fault_pc; - register struct proc *p; - register struct pcb *pcb; - u_int fault_instruction; - pt_entry_t *pte; - int error; - - /* - * Enable IRQ's (disabled by the abort) This always comes - * from user mode so we know interrupts were not disabled. - * But we check anyway. - */ - if (!(frame->tf_spsr & I32_bit)) - enable_interrupts(I32_bit); - -#ifdef DEBUG - if ((GetCPSR() & PSR_MODE) != PSR_SVC32_MODE) - panic("prefetch_abort_handler: not in SVC32 mode"); -#endif - - /* Update vmmeter statistics */ - uvmexp.traps++; - - /* Call the cpu specific abort fixup routine */ - error = cpu_prefetchabt_fixup(frame); - if (error == ABORT_FIXUP_RETURN) - return; - if (error == ABORT_FIXUP_FAILED) - panic("prefetch abort fixup failed\n"); - - /* Get the current proc structure or proc0 if there is none */ - if ((p = curproc) == 0) { - p = &proc0; -#ifdef DEBUG - printf("Prefetch abort with curproc == 0\n"); -#endif - } - -#ifdef PMAP_DEBUG - if (pmap_debug_level >= 0) - printf("prefetch fault in process %p %s\n", p, p->p_comm); -#endif - /* - * can't use curpcb, as it might be NULL; and we have p in a - * register anyway - */ - pcb = &p->p_addr->u_pcb; - if (pcb == 0) - panic("prefetch_abort_handler: no pcb ... we're toast !\n"); - -#ifdef DEBUG - if (pcb != curpcb) { - printf("data_abort: Alert ! pcb(%p) != curpcb(%p)\n", - pcb, curpcb); - printf("data_abort: Alert ! proc(%p), curproc(%p)\n", - p, curproc); - } -#endif /* DEBUG */ - - /* Was the prefectch abort from USR32 mode ? */ - - if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) { - p->p_addr->u_pcb.pcb_tf = frame; - } else { - /* - * All the kernel code pages are loaded at boot time - * and do not get paged - */ - panic("Prefetch abort in non-USR mode (frame=%p)\n", frame); - } - - /* Get fault address */ - fault_pc = frame->tf_pc; - -#ifdef PMAP_DEBUG - if (pmap_debug_level >= 0) - printf("prefetch_abort: PC = %08x\n", fault_pc); -#endif - /* Ok validate the address, can only execute in USER space */ - if (fault_pc < VM_MIN_ADDRESS || fault_pc >= VM_MAXUSER_ADDRESS) { -#ifdef DEBUG - printf("prefetch: pc (%08x) not in user process space\n", - fault_pc); -#endif - trapsignal(p, SIGSEGV, fault_pc); - userret(p); - return; - } - - /* Is the page already mapped ? */ - /* This is debugging for rev K SA110 silicon */ - pte = pmap_pte(p->p_vmspace->vm_map.pmap, (vaddr_t)fault_pc); - if (pte && *pte != 0) { - if (kernel_debug & 1) { - printf("prefetch_abort: page is already mapped - pte=%p *pte=%08x\n", - pte, *pte); - printf("prefetch_abort: pc=%08x proc=%p process=%s\n", fault_pc, p, p->p_comm); - printf("prefetch_abort: far=%08x fs=%x\n", cpu_faultaddress(), cpu_faultstatus()); - printf("prefetch_abort: trapframe=%08x\n", (u_int)frame); - } -#ifdef DDB - if (kernel_debug & 2) - Debugger(); -#endif - } - - /* Ok read the fault address. This will fault the page in for us */ - if (fetchuserword(fault_pc, &fault_instruction) != 0) { -#ifdef DEBUG - printf("prefetch: faultin failed for address %08x\n", - fault_pc); -#endif - trapsignal(p, SIGSEGV, fault_pc); - } else { - -#ifdef DIAGNOSTIC - /* More debug stuff */ - -#ifdef PMAP_DEBUG - if (pmap_debug_level >= 0) { - printf("Instruction @V%08x = %08x\n", fault_pc, - fault_instruction); - disassemble(fault_pc); - printf("return addr=%08x", frame->tf_pc); - pte = pmap_pte(p->p_vmspace->vm_map.pmap, - (vaddr_t)fault_pc); - if (pte) - printf(" pte=%p *pte=%08x\n", pte, *pte); - else - printf("\n"); - - } -#endif /* PMAP_DEBUG */ -#endif /* DIAGNOSTIC */ - } - - userret(p); -} - -int -cowfault(va) - vaddr_t va; -{ - struct vmspace *vm; - int error; - - if (va >= VM_MAXUSER_ADDRESS) - return (EFAULT); - - /* uvm_fault can't be called from within an interrupt */ - KASSERT(current_intr_depth == 0); - - vm = curproc->p_vmspace; - error = uvm_fault(&vm->vm_map, va, 0, VM_PROT_READ | VM_PROT_WRITE); - return error; -} - -/* End of fault.c */