Home | History | Annotate | Line # | Download | only in arm32
fault.c revision 1.28
      1  1.28   briggs /*	$NetBSD: fault.c,v 1.28 2003/04/28 01:54:50 briggs Exp $	*/
      2   1.1    chris 
      3   1.1    chris /*
      4  1.27      scw  * Copyright 2003 Wasabi Systems, Inc.
      5  1.27      scw  * All rights reserved.
      6  1.27      scw  *
      7  1.27      scw  * Written by Steve C. Woodford for Wasabi Systems, Inc.
      8  1.27      scw  *
      9  1.27      scw  * Redistribution and use in source and binary forms, with or without
     10  1.27      scw  * modification, are permitted provided that the following conditions
     11  1.27      scw  * are met:
     12  1.27      scw  * 1. Redistributions of source code must retain the above copyright
     13  1.27      scw  *    notice, this list of conditions and the following disclaimer.
     14  1.27      scw  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.27      scw  *    notice, this list of conditions and the following disclaimer in the
     16  1.27      scw  *    documentation and/or other materials provided with the distribution.
     17  1.27      scw  * 3. All advertising materials mentioning features or use of this software
     18  1.27      scw  *    must display the following acknowledgement:
     19  1.27      scw  *      This product includes software developed for the NetBSD Project by
     20  1.27      scw  *      Wasabi Systems, Inc.
     21  1.27      scw  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     22  1.27      scw  *    or promote products derived from this software without specific prior
     23  1.27      scw  *    written permission.
     24  1.27      scw  *
     25  1.27      scw  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     26  1.27      scw  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27  1.27      scw  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28  1.27      scw  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     29  1.27      scw  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30  1.27      scw  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31  1.27      scw  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32  1.27      scw  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33  1.27      scw  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34  1.27      scw  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35  1.27      scw  * POSSIBILITY OF SUCH DAMAGE.
     36  1.27      scw  */
     37  1.27      scw /*
     38   1.1    chris  * Copyright (c) 1994-1997 Mark Brinicombe.
     39   1.1    chris  * Copyright (c) 1994 Brini.
     40   1.1    chris  * All rights reserved.
     41   1.1    chris  *
     42   1.1    chris  * This code is derived from software written for Brini by Mark Brinicombe
     43   1.1    chris  *
     44   1.1    chris  * Redistribution and use in source and binary forms, with or without
     45   1.1    chris  * modification, are permitted provided that the following conditions
     46   1.1    chris  * are met:
     47   1.1    chris  * 1. Redistributions of source code must retain the above copyright
     48   1.1    chris  *    notice, this list of conditions and the following disclaimer.
     49   1.1    chris  * 2. Redistributions in binary form must reproduce the above copyright
     50   1.1    chris  *    notice, this list of conditions and the following disclaimer in the
     51   1.1    chris  *    documentation and/or other materials provided with the distribution.
     52   1.1    chris  * 3. All advertising materials mentioning features or use of this software
     53   1.1    chris  *    must display the following acknowledgement:
     54   1.1    chris  *	This product includes software developed by Brini.
     55   1.1    chris  * 4. The name of the company nor the name of the author may be used to
     56   1.1    chris  *    endorse or promote products derived from this software without specific
     57   1.1    chris  *    prior written permission.
     58   1.1    chris  *
     59   1.1    chris  * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
     60   1.1    chris  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     61   1.1    chris  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     62   1.1    chris  * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     63   1.1    chris  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     64   1.1    chris  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     65   1.1    chris  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     66   1.1    chris  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     67   1.1    chris  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     68   1.1    chris  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     69   1.1    chris  * SUCH DAMAGE.
     70   1.1    chris  *
     71   1.1    chris  * RiscBSD kernel project
     72   1.1    chris  *
     73   1.1    chris  * fault.c
     74   1.1    chris  *
     75   1.1    chris  * Fault handlers
     76   1.1    chris  *
     77   1.1    chris  * Created      : 28/11/94
     78   1.1    chris  */
     79   1.1    chris 
     80   1.1    chris #include "opt_ddb.h"
     81  1.28   briggs #include "opt_kgdb.h"
     82   1.1    chris #include "opt_pmap_debug.h"
     83   1.1    chris 
     84   1.1    chris #include <sys/types.h>
     85  1.28   briggs __KERNEL_RCSID(0, "$NetBSD: fault.c,v 1.28 2003/04/28 01:54:50 briggs Exp $");
     86  1.21    bjh21 
     87   1.1    chris #include <sys/param.h>
     88   1.1    chris #include <sys/systm.h>
     89   1.1    chris #include <sys/proc.h>
     90   1.1    chris #include <sys/user.h>
     91   1.1    chris #include <sys/kernel.h>
     92   1.1    chris 
     93   1.1    chris #include <uvm/uvm_extern.h>
     94  1.18  thorpej 
     95  1.18  thorpej #include <arm/cpuconf.h>
     96   1.1    chris 
     97   1.1    chris #include <machine/frame.h>
     98   1.5  thorpej #include <arm/arm32/katelib.h>
     99   1.1    chris #include <machine/cpu.h>
    100   1.2     matt #include <machine/intr.h>
    101  1.28   briggs #if defined(DDB) || defined(KGDB)
    102   1.1    chris #include <machine/db_machdep.h>
    103  1.28   briggs #ifdef KGDB
    104  1.28   briggs #include <sys/kgdb.h>
    105  1.28   briggs #endif
    106  1.28   briggs #if !defined(DDB)
    107  1.28   briggs #define kdb_trap	kgdb_trap
    108  1.28   briggs #endif
    109   1.1    chris #endif
    110   1.1    chris 
    111   1.1    chris #include <arch/arm/arm/disassem.h>
    112   1.7    chris #include <arm/arm32/machdep.h>
    113   1.7    chris 
    114   1.1    chris extern char fusubailout[];
    115   1.1    chris 
    116  1.27      scw #ifdef DEBUG
    117  1.27      scw int last_fault_code;	/* For the benefit of pmap_fault_fixup() */
    118  1.27      scw #endif
    119  1.27      scw 
    120   1.7    chris static void report_abort __P((const char *, u_int, u_int, u_int));
    121   1.7    chris 
    122   1.1    chris /* Abort code */
    123   1.1    chris 
    124   1.1    chris /* Define text descriptions of the different aborts */
    125   1.1    chris 
    126   1.1    chris static const char *aborts[16] = {
    127   1.1    chris 	"Write buffer fault",
    128   1.1    chris 	"Alignment fault",
    129   1.1    chris 	"Write buffer fault",
    130   1.1    chris 	"Alignment fault",
    131   1.1    chris 	"Bus error (LF section)",
    132   1.1    chris 	"Translation fault (section)",
    133   1.1    chris 	"Bus error (page)",
    134   1.1    chris 	"Translation fault (page)",
    135   1.1    chris 	"Bus error (section)",
    136   1.1    chris 	"Domain error (section)",
    137   1.1    chris 	"Bus error (page)",
    138   1.1    chris 	"Domain error (page)",
    139   1.1    chris 	"Bus error trans (L1)",
    140   1.1    chris 	"Permission error (section)",
    141   1.1    chris 	"Bus error trans (L2)",
    142   1.1    chris 	"Permission error (page)"
    143   1.1    chris };
    144   1.1    chris 
    145   1.7    chris static void
    146   1.1    chris report_abort(prefix, fault_status, fault_address, fault_pc)
    147   1.1    chris 	const char *prefix;
    148   1.1    chris 	u_int fault_status;
    149   1.1    chris 	u_int fault_address;
    150   1.1    chris 	u_int fault_pc;
    151   1.1    chris {
    152   1.1    chris #ifndef DEBUG
    153   1.1    chris 	if (prefix == NULL) {
    154   1.1    chris #endif
    155   1.1    chris 		if (prefix)
    156   1.1    chris 			printf("%s ", prefix);
    157   1.1    chris 		printf("Data abort: '%s' status=%03x address=%08x PC=%08x\n",
    158   1.1    chris 		    aborts[fault_status & FAULT_TYPE_MASK],
    159   1.1    chris 		    fault_status & 0xfff, fault_address, fault_pc);
    160   1.1    chris #ifndef DEBUG
    161   1.1    chris 	}
    162   1.1    chris #endif
    163   1.1    chris }
    164   1.1    chris 
    165   1.3  thorpej static __volatile int data_abort_expected;
    166   1.3  thorpej static __volatile int data_abort_received;
    167   1.3  thorpej 
    168   1.3  thorpej int
    169   1.3  thorpej badaddr_read(void *addr, size_t size, void *rptr)
    170   1.3  thorpej {
    171   1.3  thorpej 	u_long rcpt;
    172   1.3  thorpej 	int rv;
    173   1.3  thorpej 
    174   1.3  thorpej 	/* Tell the Data Abort handler that we're expecting one. */
    175   1.3  thorpej 	data_abort_received = 0;
    176   1.3  thorpej 	data_abort_expected = 1;
    177   1.3  thorpej 
    178   1.3  thorpej 	cpu_drain_writebuf();
    179   1.3  thorpej 
    180   1.3  thorpej 	/* Read from the test address. */
    181   1.3  thorpej 	switch (size) {
    182   1.3  thorpej 	case sizeof(uint8_t):
    183   1.3  thorpej 		__asm __volatile("ldrb %0, [%1]"
    184   1.3  thorpej 			: "=r" (rcpt)
    185   1.3  thorpej 			: "r" (addr));
    186   1.3  thorpej 		break;
    187   1.3  thorpej 
    188   1.3  thorpej 	case sizeof(uint16_t):
    189   1.3  thorpej 		__asm __volatile("ldrh %0, [%1]"
    190   1.3  thorpej 			: "=r" (rcpt)
    191   1.3  thorpej 			: "r" (addr));
    192   1.3  thorpej 		break;
    193   1.3  thorpej 
    194   1.3  thorpej 	case sizeof(uint32_t):
    195   1.3  thorpej 		__asm __volatile("ldr %0, [%1]"
    196   1.3  thorpej 			: "=r" (rcpt)
    197   1.3  thorpej 			: "r" (addr));
    198   1.3  thorpej 		break;
    199   1.3  thorpej 
    200   1.3  thorpej 	default:
    201   1.3  thorpej 		data_abort_expected = 0;
    202  1.24   provos 		panic("badaddr: invalid size (%lu)", (u_long) size);
    203   1.3  thorpej 	}
    204   1.3  thorpej 
    205   1.3  thorpej 	/* Disallow further Data Aborts. */
    206   1.3  thorpej 	data_abort_expected = 0;
    207   1.3  thorpej 
    208   1.3  thorpej 	rv = data_abort_received;
    209   1.3  thorpej 	data_abort_received = 0;
    210   1.3  thorpej 
    211   1.3  thorpej 	/* Copy the data back if no fault occurred. */
    212   1.3  thorpej 	if (rptr != NULL && rv == 0) {
    213   1.3  thorpej 		switch (size) {
    214   1.3  thorpej 		case sizeof(uint8_t):
    215   1.3  thorpej 			*(uint8_t *) rptr = rcpt;
    216   1.3  thorpej 			break;
    217   1.3  thorpej 
    218   1.3  thorpej 		case sizeof(uint16_t):
    219   1.3  thorpej 			*(uint16_t *) rptr = rcpt;
    220   1.3  thorpej 			break;
    221   1.3  thorpej 
    222   1.3  thorpej 		case sizeof(uint32_t):
    223   1.3  thorpej 			*(uint32_t *) rptr = rcpt;
    224   1.3  thorpej 			break;
    225   1.3  thorpej 		}
    226   1.3  thorpej 	}
    227   1.3  thorpej 
    228   1.3  thorpej 	/* Return true if the address was invalid. */
    229   1.3  thorpej 	return (rv);
    230   1.3  thorpej }
    231   1.3  thorpej 
    232   1.1    chris /*
    233   1.1    chris  * void data_abort_handler(trapframe_t *frame)
    234   1.1    chris  *
    235   1.1    chris  * Abort handler called when read/write occurs at an address of
    236   1.1    chris  * a non existent or restricted (access permissions) memory page.
    237   1.1    chris  * We first need to identify the type of page fault.
    238   1.1    chris  */
    239   1.1    chris 
    240   1.1    chris #define TRAP_CODE ((fault_status & 0x0f) | (fault_address & 0xfffffff0))
    241   1.1    chris 
    242  1.27      scw /* Determine if we can recover from a fault */
    243  1.27      scw #ifdef ARM32_PMAP_NEW
    244  1.27      scw #define	IS_FATAL_FAULT(x)					\
    245  1.27      scw 	(((1 << (x)) &						\
    246  1.27      scw 	  ((1 << FAULT_WRTBUF_0) | (1 << FAULT_WRTBUF_1) |	\
    247  1.27      scw 	   (1 << FAULT_BUSERR_0) | (1 << FAULT_BUSERR_1) |	\
    248  1.27      scw 	   (1 << FAULT_BUSERR_2) | (1 << FAULT_BUSERR_3) |	\
    249  1.27      scw 	   (1 << FAULT_BUSTRNL1) | (1 << FAULT_BUSTRNL2) |	\
    250  1.27      scw 	   (1 << FAULT_ALIGN_0)  | (1 << FAULT_ALIGN_1))) != 0)
    251  1.27      scw #else
    252  1.27      scw #define	IS_FATAL_FAULT(x)					\
    253  1.27      scw 	(((1 << (x)) &						\
    254  1.27      scw 	  ((1 << FAULT_WRTBUF_0) | (1 << FAULT_WRTBUF_1) |	\
    255  1.27      scw 	   (1 << FAULT_BUSERR_0) | (1 << FAULT_BUSERR_1) |	\
    256  1.27      scw 	   (1 << FAULT_BUSERR_2) | (1 << FAULT_BUSERR_3) |	\
    257  1.27      scw 	   (1 << FAULT_BUSTRNL1) | (1 << FAULT_BUSTRNL2) |	\
    258  1.27      scw 	   (1 << FAULT_DOMAIN_S) | (1 << FAULT_DOMAIN_P) |	\
    259  1.27      scw 	   (1 << FAULT_ALIGN_0)  | (1 << FAULT_ALIGN_1))) != 0)
    260  1.27      scw #endif
    261  1.27      scw 
    262   1.1    chris void
    263   1.1    chris data_abort_handler(frame)
    264   1.1    chris 	trapframe_t *frame;
    265   1.1    chris {
    266  1.26  thorpej 	struct lwp *l;
    267   1.1    chris 	struct proc *p;
    268   1.1    chris 	struct pcb *pcb;
    269   1.1    chris 	u_int fault_address;
    270   1.1    chris 	u_int fault_status;
    271   1.1    chris 	u_int fault_pc;
    272   1.1    chris 	u_int fault_instruction;
    273  1.27      scw 	int fault_code, fatal_fault;
    274   1.1    chris 	int user;
    275   1.1    chris 	int error;
    276  1.27      scw 	int rv;
    277   1.1    chris 	void *onfault;
    278  1.27      scw 	vaddr_t va;
    279  1.27      scw 	struct vmspace *vm;
    280  1.27      scw 	struct vm_map *map;
    281  1.27      scw 	vm_prot_t ftype;
    282  1.27      scw 	extern struct vm_map *kernel_map;
    283   1.3  thorpej 
    284   1.3  thorpej 	/*
    285   1.3  thorpej 	 * If we were expecting a Data Abort, signal that we got
    286   1.3  thorpej 	 * one, adjust the PC to skip the faulting insn, and
    287   1.3  thorpej 	 * return.
    288   1.3  thorpej 	 */
    289   1.3  thorpej 	if (data_abort_expected) {
    290   1.3  thorpej 		data_abort_received = 1;
    291   1.3  thorpej 		frame->tf_pc += INSN_SIZE;
    292   1.3  thorpej 		return;
    293   1.3  thorpej 	}
    294   1.1    chris 
    295   1.1    chris 	/*
    296   1.1    chris 	 * Must get fault address and status from the CPU before
    297   1.1    chris 	 * re-enabling interrupts.  (Interrupt handlers may take
    298   1.1    chris 	 * R/M emulation faults.)
    299   1.1    chris 	 */
    300   1.1    chris 	fault_address = cpu_faultaddress();
    301   1.1    chris 	fault_status = cpu_faultstatus();
    302   1.1    chris 	fault_pc = frame->tf_pc;
    303   1.1    chris 
    304   1.1    chris 	/*
    305   1.1    chris 	 * Enable IRQ's (disabled by CPU on abort) if trapframe
    306   1.1    chris 	 * shows they were enabled.
    307   1.1    chris 	 */
    308   1.1    chris 	if (!(frame->tf_spsr & I32_bit))
    309   1.1    chris 		enable_interrupts(I32_bit);
    310   1.1    chris 
    311   1.1    chris #ifdef DEBUG
    312   1.1    chris 	if ((GetCPSR() & PSR_MODE) != PSR_SVC32_MODE)
    313   1.1    chris 		panic("data_abort_handler: not in SVC32 mode");
    314   1.1    chris #endif
    315   1.1    chris 
    316   1.1    chris 	/* Update vmmeter statistics */
    317   1.1    chris 	uvmexp.traps++;
    318   1.1    chris 
    319   1.1    chris 	/* Extract the fault code from the fault status */
    320   1.1    chris 	fault_code = fault_status & FAULT_TYPE_MASK;
    321  1.27      scw 	fatal_fault = IS_FATAL_FAULT(fault_code);
    322   1.1    chris 
    323  1.26  thorpej 	/* Get the current lwp structure or lwp0 if there is none */
    324  1.26  thorpej 	l = curlwp == NULL ? &lwp0 : curlwp;
    325  1.26  thorpej 	p = l->l_proc;
    326   1.1    chris 
    327   1.1    chris 	/*
    328   1.1    chris 	 * can't use curpcb, as it might be NULL; and we have p in
    329   1.1    chris 	 * a register anyway
    330   1.1    chris 	 */
    331  1.26  thorpej 	pcb = &l->l_addr->u_pcb;
    332   1.1    chris 
    333   1.1    chris 	/* fusubailout is used by [fs]uswintr to avoid page faulting */
    334  1.27      scw 	if (pcb->pcb_onfault &&
    335  1.27      scw 	    (fatal_fault || pcb->pcb_onfault == fusubailout)) {
    336   1.1    chris 
    337  1.20    bjh21 		frame->tf_r0 = EFAULT;
    338   1.1    chris copyfault:
    339   1.1    chris #ifdef DEBUG
    340  1.26  thorpej 		printf("Using pcb_onfault=%p addr=%08x st=%08x l=%p\n",
    341  1.26  thorpej 		    pcb->pcb_onfault, fault_address, fault_status, l);
    342   1.1    chris #endif
    343   1.1    chris 		frame->tf_pc = (u_int)pcb->pcb_onfault;
    344   1.1    chris 		if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE)
    345  1.24   provos 			panic("Yikes pcb_onfault=%p during USR mode fault",
    346   1.1    chris 			    pcb->pcb_onfault);
    347   1.1    chris 		return;
    348   1.1    chris 	}
    349   1.1    chris 
    350   1.1    chris 	/* More debug stuff */
    351   1.1    chris 
    352   1.1    chris 	fault_instruction = ReadWord(fault_pc);
    353   1.1    chris 
    354   1.1    chris #ifdef PMAP_DEBUG
    355   1.1    chris 	if (pmap_debug_level >= 0) {
    356   1.1    chris 		report_abort(NULL, fault_status, fault_address, fault_pc);
    357   1.1    chris 		printf("Instruction @V%08x = %08x\n",
    358   1.1    chris 		    fault_pc, fault_instruction);
    359   1.1    chris 	}
    360   1.1    chris #endif
    361   1.1    chris 
    362   1.1    chris 	/* Call the cpu specific abort fixup routine */
    363   1.1    chris 	error = cpu_dataabt_fixup(frame);
    364   1.1    chris 	if (error == ABORT_FIXUP_RETURN)
    365   1.1    chris 		return;
    366   1.1    chris 	if (error == ABORT_FIXUP_FAILED) {
    367  1.11  reinoud 		printf("pc = 0x%08x, opcode 0x%08x, insn = ", fault_pc, *((u_int *)fault_pc));
    368   1.1    chris 		disassemble(fault_pc);
    369  1.11  reinoud 		printf("data abort handler: fixup failed for this instruction\n");
    370   1.1    chris 	}
    371   1.1    chris 
    372   1.1    chris #ifdef PMAP_DEBUG
    373   1.1    chris 	if (pmap_debug_level >= 0)
    374   1.1    chris 		printf("fault in process %p\n", p);
    375   1.1    chris #endif
    376   1.1    chris 
    377   1.1    chris #ifdef DEBUG
    378  1.27      scw 	/* Is this needed ? (XXXSCW: yes. can happen during boot ...) */
    379  1.27      scw 	if (!cold && pcb != curpcb) {
    380   1.1    chris 		printf("data_abort: Alert ! pcb(%p) != curpcb(%p)\n",
    381   1.1    chris 		    pcb, curpcb);
    382  1.26  thorpej 		printf("data_abort: Alert ! proc(%p), curlwp(%p)\n",
    383  1.26  thorpej 		    p, curlwp);
    384   1.1    chris 	}
    385   1.1    chris #endif	/* DEBUG */
    386   1.1    chris 
    387   1.1    chris 	/* Were we in user mode when the abort occurred ? */
    388   1.1    chris 	if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
    389   1.1    chris 		/*
    390   1.1    chris 		 * Note that the fault was from USR mode.
    391   1.1    chris 		 */
    392   1.1    chris 		user = 1;
    393  1.26  thorpej 		l->l_addr->u_pcb.pcb_tf = frame;
    394   1.1    chris 	} else
    395   1.1    chris 		user = 0;
    396  1.11  reinoud 
    397  1.11  reinoud 	/* check if this was a failed fixup */
    398  1.11  reinoud 	if (error == ABORT_FIXUP_FAILED) {
    399  1.11  reinoud 		if (user) {
    400  1.26  thorpej 			trapsignal(l, SIGSEGV, TRAP_CODE);
    401  1.26  thorpej 			userret(l);
    402  1.11  reinoud 			return;
    403  1.11  reinoud 		};
    404  1.24   provos 		panic("Data abort fixup failed in kernel - we're dead");
    405  1.11  reinoud 	};
    406   1.1    chris 
    407   1.1    chris 	/* Now act on the fault type */
    408  1.27      scw 	if (fatal_fault) {
    409   1.1    chris 		/*
    410  1.27      scw 		 * None of these faults should happen on a perfectly
    411  1.27      scw 		 * functioning system. They indicate either some gross
    412  1.27      scw 		 * problem with the kernel, or a hardware problem.
    413  1.27      scw 		 * In either case, stop.
    414   1.1    chris 		 */
    415   1.1    chris 		report_abort(NULL, fault_status, fault_address, fault_pc);
    416   1.1    chris 
    417  1.27      scw we_re_toast:
    418   1.1    chris 		/*
    419   1.1    chris 		 * Were are dead, try and provide some debug
    420   1.1    chris 		 * information before dying.
    421   1.1    chris 		 */
    422  1.28   briggs #if defined(DDB) || defined(KGDB)
    423   1.1    chris 		printf("Unhandled trap (frame = %p)\n", frame);
    424   1.1    chris 		report_abort(NULL, fault_status, fault_address, fault_pc);
    425   1.1    chris 		kdb_trap(-1, frame);
    426   1.1    chris 		return;
    427   1.1    chris #else
    428   1.1    chris 		panic("Unhandled trap (frame = %p)", frame);
    429  1.28   briggs #endif	/* DDB || KGDB */
    430  1.27      scw 	}
    431  1.27      scw 
    432   1.1    chris 	/*
    433  1.27      scw 	 * At this point, we're dealing with one of the following faults:
    434  1.27      scw 	 *
    435  1.27      scw 	 *  FAULT_TRANS_P	Page Translation Fault
    436  1.27      scw 	 *  FAULT_PERM_P	Page Permission Fault
    437  1.27      scw 	 *  FAULT_TRANS_S	Section Translation Fault
    438  1.27      scw 	 *  FAULT_PERM_S	Section Permission Fault
    439  1.27      scw 	 *
    440  1.27      scw 	 * And if ARM32_PMAP_NEW is in effect:
    441  1.27      scw 	 *
    442  1.27      scw 	 *  FAULT_DOMAIN_P	Page Domain Error Fault
    443  1.27      scw 	 *  FAULT_DOMAIN_S	Section Domain Error Fault
    444  1.27      scw 	 *
    445   1.1    chris 	 * Page/section translation/permission fault -- need to fault in
    446  1.27      scw 	 * the page.
    447  1.27      scw 	 *
    448  1.27      scw 	 * Page/section domain fault -- need to see if the L1 entry can
    449  1.27      scw 	 * be fixed up.
    450   1.1    chris 	 */
    451  1.27      scw 	vm = p->p_vmspace;
    452  1.27      scw 	va = trunc_page((vaddr_t)fault_address);
    453   1.1    chris 
    454   1.1    chris #ifdef PMAP_DEBUG
    455  1.27      scw 	if (pmap_debug_level >= 0)
    456  1.27      scw 		printf("page fault: addr=V%08lx ", va);
    457   1.1    chris #endif
    458   1.1    chris 
    459  1.27      scw 	/*
    460  1.27      scw 	 * It is only a kernel address space fault iff:
    461  1.27      scw 	 *	1. user == 0  and
    462  1.27      scw 	 *	2. pcb_onfault not set or
    463  1.27      scw 	 *	3. pcb_onfault set but supervisor space fault
    464  1.27      scw 	 * The last can occur during an exec() copyin where the
    465  1.27      scw 	 * argument space is lazy-allocated.
    466  1.27      scw 	 */
    467  1.27      scw 	if (!user &&
    468  1.27      scw 	    (va >= VM_MIN_KERNEL_ADDRESS || va < VM_MIN_ADDRESS)) {
    469  1.27      scw 		/* Was the fault due to the FPE/IPKDB ? */
    470  1.27      scw 		if ((frame->tf_spsr & PSR_MODE) == PSR_UND32_MODE) {
    471  1.27      scw 			report_abort("UND32", fault_status,
    472  1.27      scw 			    fault_address, fault_pc);
    473  1.27      scw 			trapsignal(l, SIGSEGV, TRAP_CODE);
    474  1.27      scw 
    475  1.27      scw 			/*
    476  1.27      scw 			 * Force exit via userret()
    477  1.27      scw 			 * This is necessary as the FPE is an extension
    478  1.27      scw 			 * to userland that actually runs in a
    479  1.27      scw 			 * priveledged mode but uses USR mode
    480  1.27      scw 			 * permissions for its accesses.
    481  1.27      scw 			 */
    482  1.27      scw 			userret(l);
    483  1.27      scw 			return;
    484  1.27      scw 		}
    485  1.27      scw 		map = kernel_map;
    486  1.27      scw 	} else
    487  1.27      scw 		map = &vm->vm_map;
    488   1.1    chris 
    489   1.1    chris #ifdef PMAP_DEBUG
    490  1.27      scw 	if (pmap_debug_level >= 0)
    491  1.27      scw 		printf("vmmap=%p ", map);
    492   1.1    chris #endif
    493   1.1    chris 
    494  1.27      scw 	if (map == NULL)
    495  1.27      scw 		printf("No map for fault address va = 0x%08lx", va);
    496   1.1    chris 
    497  1.27      scw 	/*
    498  1.27      scw 	 * We need to know whether the page should be mapped
    499  1.27      scw 	 * as R or R/W. The MMU does not give us the info as
    500  1.27      scw 	 * to whether the fault was caused by a read or a write.
    501  1.27      scw 	 * This means we need to disassemble the instruction
    502  1.27      scw 	 * responsible and determine if it was a read or write
    503  1.27      scw 	 * instruction.
    504  1.27      scw 	 */
    505  1.27      scw 	/* STR instruction ? */
    506  1.27      scw 	if ((fault_instruction & 0x0c100000) == 0x04000000)
    507  1.27      scw 		ftype = VM_PROT_WRITE;
    508  1.27      scw 	/* STM or CDT instruction ? */
    509  1.27      scw 	else if ((fault_instruction & 0x0a100000) == 0x08000000)
    510  1.27      scw 		ftype = VM_PROT_WRITE;
    511  1.27      scw 	/* STRH, STRSH or STRSB instruction ? */
    512  1.27      scw 	else if ((fault_instruction & 0x0e100090) == 0x00000090)
    513  1.27      scw 		ftype = VM_PROT_WRITE;
    514  1.27      scw 	/* SWP instruction ? */
    515  1.27      scw 	else if ((fault_instruction & 0x0fb00ff0) == 0x01000090)
    516  1.27      scw 		ftype = VM_PROT_READ | VM_PROT_WRITE;
    517  1.27      scw 	else
    518  1.27      scw 		ftype = VM_PROT_READ;
    519   1.1    chris 
    520   1.1    chris #ifdef PMAP_DEBUG
    521  1.27      scw 	if (pmap_debug_level >= 0)
    522  1.27      scw 		printf("fault protection = %d\n", ftype);
    523   1.1    chris #endif
    524   1.1    chris 
    525  1.27      scw #ifndef ARM32_PMAP_NEW
    526  1.27      scw 	if ((ftype & VM_PROT_WRITE) ?
    527  1.27      scw 	    pmap_modified_emulation(map->pmap, va) :
    528  1.27      scw 	    pmap_handled_emulation(map->pmap, va))
    529  1.27      scw 		goto out;
    530  1.27      scw #else
    531  1.27      scw 	if (pmap_fault_fixup(map->pmap, va, ftype))
    532  1.27      scw 		goto out;
    533  1.27      scw #endif
    534   1.1    chris 
    535  1.27      scw 	if (current_intr_depth > 0) {
    536  1.28   briggs #if defined(DDB) || defined(KGDB)
    537  1.27      scw 		printf("Non-emulated page fault with intr_depth > 0\n");
    538  1.27      scw 		report_abort(NULL, fault_status, fault_address, fault_pc);
    539  1.27      scw 		kdb_trap(-1, frame);
    540  1.27      scw 		return;
    541   1.1    chris #else
    542  1.27      scw 		panic("Fault with intr_depth > 0");
    543   1.1    chris #endif	/* DDB */
    544  1.27      scw 	}
    545   1.1    chris 
    546  1.27      scw 	onfault = pcb->pcb_onfault;
    547  1.27      scw 	pcb->pcb_onfault = NULL;
    548  1.27      scw 	rv = uvm_fault(map, va, 0, ftype);
    549  1.27      scw 	pcb->pcb_onfault = onfault;
    550  1.27      scw 	if (rv == 0) {
    551  1.27      scw 		if (user != 0) /* Record any stack growth... */
    552  1.27      scw 			uvm_grow(p, trunc_page(va));
    553  1.27      scw 		goto out;
    554  1.27      scw 	}
    555  1.27      scw 	if (user == 0) {
    556  1.27      scw 		if (pcb->pcb_onfault) {
    557  1.27      scw 			frame->tf_r0 = rv;
    558  1.27      scw 			goto copyfault;
    559   1.1    chris 		}
    560  1.27      scw 		printf("[u]vm_fault(%p, %lx, %x, 0) -> %x\n", map, va, ftype,
    561  1.27      scw 		    rv);
    562  1.27      scw 		goto we_re_toast;
    563  1.27      scw 	}
    564   1.1    chris 
    565  1.27      scw 	report_abort("", fault_status, fault_address, fault_pc);
    566  1.27      scw 	if (rv == ENOMEM) {
    567  1.27      scw 		printf("UVM: pid %d (%s), uid %d killed: "
    568  1.27      scw 		    "out of swap\n", p->p_pid, p->p_comm,
    569  1.27      scw 		    (p->p_cred && p->p_ucred) ?  p->p_ucred->cr_uid : -1);
    570  1.26  thorpej 			trapsignal(l, SIGKILL, TRAP_CODE);
    571  1.27      scw 	} else
    572  1.27      scw 		trapsignal(l, SIGSEGV, TRAP_CODE);
    573  1.27      scw 
    574  1.27      scw out:
    575   1.1    chris 	/* Call userret() if it was a USR mode fault */
    576   1.1    chris 	if (user)
    577  1.26  thorpej 		userret(l);
    578   1.1    chris }
    579   1.1    chris 
    580   1.1    chris 
    581   1.1    chris /*
    582   1.1    chris  * void prefetch_abort_handler(trapframe_t *frame)
    583   1.1    chris  *
    584   1.1    chris  * Abort handler called when instruction execution occurs at
    585   1.1    chris  * a non existent or restricted (access permissions) memory page.
    586   1.1    chris  * If the address is invalid and we were in SVC mode then panic as
    587   1.1    chris  * the kernel should never prefetch abort.
    588   1.1    chris  * If the address is invalid and the page is mapped then the user process
    589   1.1    chris  * does no have read permission so send it a signal.
    590   1.1    chris  * Otherwise fault the page in and try again.
    591   1.1    chris  */
    592   1.1    chris 
    593   1.1    chris void
    594   1.1    chris prefetch_abort_handler(frame)
    595   1.1    chris 	trapframe_t *frame;
    596   1.1    chris {
    597  1.26  thorpej 	struct lwp *l;
    598  1.14  thorpej 	struct proc *p;
    599  1.14  thorpej 	struct vm_map *map;
    600  1.14  thorpej 	vaddr_t fault_pc, va;
    601   1.1    chris 	int error;
    602   1.1    chris 
    603   1.1    chris 	/*
    604   1.1    chris 	 * Enable IRQ's (disabled by the abort) This always comes
    605   1.1    chris 	 * from user mode so we know interrupts were not disabled.
    606   1.1    chris 	 * But we check anyway.
    607   1.1    chris 	 */
    608   1.1    chris 	if (!(frame->tf_spsr & I32_bit))
    609   1.1    chris 		enable_interrupts(I32_bit);
    610   1.1    chris 
    611   1.1    chris #ifdef DEBUG
    612   1.1    chris 	if ((GetCPSR() & PSR_MODE) != PSR_SVC32_MODE)
    613   1.1    chris 		panic("prefetch_abort_handler: not in SVC32 mode");
    614   1.1    chris #endif
    615   1.1    chris 
    616   1.1    chris 	/* Update vmmeter statistics */
    617   1.1    chris 	uvmexp.traps++;
    618   1.1    chris 
    619   1.1    chris 	/* Call the cpu specific abort fixup routine */
    620   1.1    chris 	error = cpu_prefetchabt_fixup(frame);
    621   1.1    chris 	if (error == ABORT_FIXUP_RETURN)
    622   1.1    chris 		return;
    623   1.1    chris 	if (error == ABORT_FIXUP_FAILED)
    624  1.24   provos 		panic("prefetch abort fixup failed");
    625   1.1    chris 
    626   1.1    chris 	/* Get the current proc structure or proc0 if there is none */
    627  1.26  thorpej 	if ((l = curlwp) == NULL) {
    628  1.26  thorpej 		l = &lwp0;
    629   1.1    chris #ifdef DEBUG
    630  1.26  thorpej 		printf("Prefetch abort with curlwp == 0\n");
    631   1.1    chris #endif
    632   1.1    chris 	}
    633  1.26  thorpej 	p = l->l_proc;
    634   1.1    chris 
    635   1.1    chris #ifdef PMAP_DEBUG
    636   1.1    chris 	if (pmap_debug_level >= 0)
    637   1.1    chris 		printf("prefetch fault in process %p %s\n", p, p->p_comm);
    638   1.1    chris #endif
    639   1.1    chris 
    640   1.4  thorpej 	/* Get fault address */
    641   1.4  thorpej 	fault_pc = frame->tf_pc;
    642  1.14  thorpej 	va = trunc_page(fault_pc);
    643   1.4  thorpej 
    644   1.1    chris 	/* Was the prefectch abort from USR32 mode ? */
    645   1.1    chris 	if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
    646  1.26  thorpej 		l->l_addr->u_pcb.pcb_tf = frame;
    647   1.1    chris 	} else {
    648   1.1    chris 		/*
    649   1.1    chris 		 * All the kernel code pages are loaded at boot time
    650   1.1    chris 		 * and do not get paged
    651   1.1    chris 		 */
    652  1.24   provos 	        panic("Prefetch abort in non-USR mode (frame=%p PC=0x%08lx)",
    653   1.4  thorpej 	            frame, fault_pc);
    654   1.1    chris 	}
    655   1.1    chris 
    656  1.14  thorpej 	map = &p->p_vmspace->vm_map;
    657  1.14  thorpej 
    658   1.1    chris #ifdef PMAP_DEBUG
    659   1.1    chris 	if (pmap_debug_level >= 0)
    660  1.16  thorpej 		printf("prefetch_abort: PC = %08lx\n", fault_pc);
    661   1.1    chris #endif
    662   1.1    chris 	/* Ok validate the address, can only execute in USER space */
    663   1.1    chris 	if (fault_pc < VM_MIN_ADDRESS || fault_pc >= VM_MAXUSER_ADDRESS) {
    664   1.1    chris #ifdef DEBUG
    665  1.19   ichiro 		printf("prefetch: pc (%08lx) not in user process space\n",
    666   1.1    chris 		    fault_pc);
    667   1.1    chris #endif
    668  1.26  thorpej 		trapsignal(l, SIGSEGV, fault_pc);
    669  1.26  thorpej 		userret(l);
    670   1.1    chris 		return;
    671   1.1    chris 	}
    672   1.1    chris 
    673  1.27      scw #ifndef ARM32_PMAP_NEW
    674  1.12  thorpej #ifdef CPU_SA110
    675  1.12  thorpej 	/*
    676  1.12  thorpej 	 * There are bugs in the rev K SA110.  This is a check for one
    677  1.12  thorpej 	 * of them.
    678  1.12  thorpej 	 */
    679  1.25    bjh21 	if (curcpu()->ci_arm_cputype == CPU_ID_SA110 &&
    680  1.25    bjh21 	    curcpu()->ci_arm_cpurev < 3) {
    681  1.12  thorpej 		/* Always current pmap */
    682  1.12  thorpej 		pt_entry_t *pte = vtopte((vaddr_t) fault_pc);
    683  1.12  thorpej 		struct pmap *pmap = p->p_vmspace->vm_map.pmap;
    684  1.12  thorpej 
    685  1.12  thorpej 		if (pmap_pde_v(pmap_pde(pmap, (vaddr_t) fault_pc)) &&
    686  1.12  thorpej 		    pmap_pte_v(pte)) {
    687  1.27      scw 			extern int kernel_debug;
    688  1.12  thorpej 			if (kernel_debug & 1) {
    689  1.12  thorpej 				printf("prefetch_abort: page is already "
    690  1.12  thorpej 				    "mapped - pte=%p *pte=%08x\n", pte, *pte);
    691  1.14  thorpej 				printf("prefetch_abort: pc=%08lx proc=%p "
    692  1.12  thorpej 				    "process=%s\n", fault_pc, p, p->p_comm);
    693  1.12  thorpej 				printf("prefetch_abort: far=%08x fs=%x\n",
    694  1.12  thorpej 				    cpu_faultaddress(), cpu_faultstatus());
    695  1.12  thorpej 				printf("prefetch_abort: trapframe=%08x\n",
    696  1.12  thorpej 				    (u_int)frame);
    697  1.12  thorpej 			}
    698  1.12  thorpej #ifdef DDB
    699  1.12  thorpej 			if (kernel_debug & 2)
    700  1.12  thorpej 				Debugger();
    701  1.17    skrll #endif
    702   1.1    chris 		}
    703   1.1    chris 	}
    704  1.12  thorpej #endif /* CPU_SA110 */
    705  1.12  thorpej 
    706  1.14  thorpej 	if (pmap_handled_emulation(map->pmap, va))
    707  1.14  thorpej 		goto out;
    708  1.14  thorpej 
    709  1.27      scw #else	/* ARM32_PMAP_NEW */
    710  1.27      scw 
    711  1.27      scw 	/*
    712  1.27      scw 	 * See if the pmap can handle this fault on its own...
    713  1.27      scw 	 */
    714  1.27      scw 	if (pmap_fault_fixup(map->pmap, va, VM_PROT_READ))
    715  1.27      scw 		goto out;
    716  1.27      scw #endif
    717  1.27      scw 
    718  1.14  thorpej 	if (current_intr_depth > 0) {
    719  1.14  thorpej #ifdef DDB
    720  1.14  thorpej 		printf("Non-emulated prefetch abort with intr_depth > 0\n");
    721  1.14  thorpej 		kdb_trap(-1, frame);
    722  1.14  thorpej 		return;
    723  1.14  thorpej #else
    724  1.14  thorpej 		panic("Prefetch Abort with intr_depth > 0");
    725   1.1    chris #endif
    726   1.1    chris 	}
    727   1.1    chris 
    728  1.14  thorpej 	error = uvm_fault(map, va, 0, VM_PROT_READ);
    729  1.14  thorpej 	if (error == 0)
    730  1.14  thorpej 		goto out;
    731  1.14  thorpej 
    732  1.14  thorpej 	if (error == ENOMEM) {
    733  1.14  thorpej 		printf("UVM: pid %d (%s), uid %d killed: "
    734  1.14  thorpej 		    "out of swap\n", p->p_pid, p->p_comm,
    735  1.27      scw 		    (p->p_cred && p->p_ucred) ?  p->p_ucred->cr_uid : -1);
    736  1.26  thorpej 		trapsignal(l, SIGKILL, fault_pc);
    737  1.14  thorpej 	} else
    738  1.26  thorpej 		trapsignal(l, SIGSEGV, fault_pc);
    739  1.27      scw out:
    740  1.26  thorpej 	userret(l);
    741   1.1    chris }
    742