NetBSD/sys/arch/arm32/arm32/fault.c

809 lines
22 KiB
C
Raw Normal View History

/* $NetBSD: fault.c,v 1.23 1998/05/01 15:44:51 mark 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 <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/kernel.h>
1997-10-17 04:09:48 +04:00
#include <vm/vm.h>
#include <vm/vm_kern.h>
#include <machine/frame.h>
#include <machine/katelib.h>
#include <machine/cpu.h>
#include <machine/pte.h>
#include <machine/irqhandler.h>
#include <arm32/arm32/disassem.h>
#ifndef POSTMORTEM
#define postmortem(x)
#endif /* POSTMORTEM */
#ifdef PMAP_DEBUG
extern int pmap_debug_level;
#endif /* PMAP_DEBUG */
int verbose_faults = 1;
int pmap_modified_emulation __P((pmap_t, vm_offset_t));
int pmap_handled_emulation __P((pmap_t, vm_offset_t));
pt_entry_t *pmap_pte __P((pmap_t pmap, vm_offset_t va));
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;
{
if (verbose_faults || prefix == NULL) {
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);
}
}
/*
* void data_abort_handler(trapframe_t *frame)
*
* Abort handler called when read/write occurs at an address of
* a non existant 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;
1996-06-04 01:53:33 +04:00
u_quad_t sticks = 0;
int error;
/*
* Enable IRQ's (disabled by CPU on abort) if trapframe
* shows they were enabled.
*/
if (!(frame->tf_spsr & I32_bit))
enable_interrupts(I32_bit);
/* Update vmmeter statistics */
cnt.v_trap++;
/* Get fault address and status from the CPU */
fault_address = cpu_faultaddress();
fault_status = cpu_faultstatus();
fault_pc = frame->tf_pc;
fault_instruction = ReadWord(fault_pc);
#ifdef DIAGNOSTIC
if (current_intr_depth > 0) {
#ifdef DDB
printf("Fault with intr_depth > 0\n");
report_abort(NULL, fault_status, fault_address, fault_pc);
printf("Instruction @V%08x = %08x\n",
fault_pc, fault_instruction);
Debugger();
#else
panic("Fault with intr_depth > 0\n");
#endif /* DDB */
}
#endif /* DIAGNOSTIC */
/* More debug stuff */
#ifdef PMAP_DEBUG
if (pmap_debug_level >= 0) {
report_abort(NULL, fault_status, fault_address, fault_pc);
1996-10-13 07:05:43 +04:00
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)
panic("data abort fixup failed\n");
/* 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;
#ifdef PMAP_DEBUG
if (pmap_debug_level >= 0)
printf("fault in process %p\n", p);
#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 == NULL) {
vm_offset_t va;
va = trunc_page((vm_offset_t)fault_address);
if (pmap_handled_emulation(kernel_pmap, va))
return;
if (pmap_modified_emulation(kernel_pmap, va))
return;
report_abort(NULL, fault_status, fault_address, fault_pc);
panic("data_abort_handler: no pcb ... we're toast !\n");
}
#ifdef DIAGNOSTIC
/* 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 /* DIAGNOSTIC */
/* fusubail is used by [fs]uswintr to avoid page faulting */
if ((pcb->pcb_onfault
&& (fault_code != FAULT_TRANS_S && fault_code != FAULT_TRANS_P))
|| pcb->pcb_onfault == fusubailout) {
copyfault:
printf("Using pcb_onfault=%p addr=%08x st=%08x p=%p\n",
pcb->pcb_onfault, fault_address, fault_status, p);
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;
}
/* Were we in user mode when the abort occurred ? */
if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
sticks = p->p_sticks;
/*
* Note that the fault was from USR mode.
*/
user = 1;
p->p_md.md_regs = 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
* infomation before dying
*/
panic("Halting (frame = %p)\n", frame);
break;
case FAULT_PERM_S: /* Section Permission Fault */
/*
* Section permission faults should not happen often.
* Only from user processes mis-behaving.
* If this happens from SVC mode then we are in trouble.
*/
if (user == 0) {
report_abort(NULL, fault_status, fault_address, fault_pc);
panic("Halting (frame = %p)\n", frame);
}
report_abort("", fault_status, fault_address, fault_pc);
trapsignal(p, SIGSEGV, TRAP_CODE);
break;
case FAULT_PERM_P: /* Page Permission Fault */
/* Ok we have a permission fault in user or kernel mode */
{
register vm_offset_t va;
register struct vmspace *vm = p->p_vmspace;
register vm_map_t map;
int rv;
vm_prot_t ftype;
/*
* Ok we have a permission fault in user mode. This will be
* caused by writing read-only pages or by reading/writing
* pages with no USR access from USR mode. This may be
* a genuine fault or it may be a bad access.
* It can also be caused software PTE modified bit emulation
*/
va = trunc_page((vm_offset_t)fault_address);
#ifdef PMAP_DEBUG
if (pmap_debug_level >= 0)
printf("page permission fault: addr=V%08lx ", va);
#endif
if (va >= VM_MAXUSER_ADDRESS && user) {
report_abort("", fault_status, fault_address, fault_pc);
trapsignal(p, SIGSEGV, TRAP_CODE);
break;
}
/*
* 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 == 0 && (va >= KERNEL_BASE || 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, frame->tf_pc, p->p_sticks);
return;
}
report_abort(NULL, fault_status, fault_address,
fault_pc);
panic("permission fault in kernel by kernel\n");
} else
map = &vm->vm_map;
#ifdef DIAGNOSTIC
if (va == 0 && map == kernel_map) {
printf("fault: bad kernel access at %lx\n", va);
goto we_re_toast;
}
#endif
#ifdef PMAP_DEBUG
if (pmap_debug_level >= 0)
printf("vmmap=%p ", map);
#endif
/*
* 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
* responcible and determine if it was a read or write
* instruction.
*/
ftype = VM_PROT_READ;
/* STR instruction ? */
if ((fault_instruction & 0x0c100000) == 0x04000000)
ftype |= VM_PROT_WRITE;
/* STM instruction ? */
else if ((fault_instruction & 0x0a100000) == 0x08000000)
ftype |= VM_PROT_WRITE;
/* SWP instruction ? */
else if ((fault_instruction & 0x0fb00ff0) == 0x01000090)
ftype |= VM_PROT_WRITE;
if (pmap_modified_emulation(map->pmap, va))
goto out;
else {
/* The page must be mapped to cause a permission fault. */
rv = vm_fault(map, va, ftype, FALSE);
#ifdef PMAP_DEBUG
if (pmap_debug_level >= 0)
1996-10-13 07:05:43 +04:00
printf("fault result=%d\n", rv);
#endif
if (rv == KERN_SUCCESS)
goto out;
report_abort("", fault_status, fault_address, fault_pc);
trapsignal(p, SIGSEGV, TRAP_CODE);
break;
}
break;
}
case FAULT_TRANS_P: /* Page Translation Fault */
/* Ok page translation fault - The page does not exist */
{
register vm_offset_t va;
register struct vmspace *vm = p->p_vmspace;
register vm_map_t map;
int rv;
vm_prot_t ftype;
extern vm_map_t kernel_map;
u_int nss;
va = trunc_page((vm_offset_t)fault_address);
#ifdef PMAP_DEBUG
if (pmap_debug_level >= 0)
printf("page fault: addr=V%08lx ", va);
#endif
if (va >= VM_MAXUSER_ADDRESS && user) {
report_abort("", fault_status, fault_address, fault_pc);
trapsignal(p, SIGSEGV, TRAP_CODE);
break;
}
/*
* 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 == 0 && (va >= KERNEL_BASE || va < VM_MIN_ADDRESS))
map = kernel_map;
else
map = &vm->vm_map;
#ifdef PMAP_DEBUG
if (pmap_debug_level >= 0)
printf("vmmap=%p ", map);
#endif
if (pmap_handled_emulation(map->pmap, va))
goto out;
/*
* 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
* responcible and determine if it was a read or write
* instruction. For the moment we will cheat and make
* it read only. If it was a write, when the instruction
* is re-executed we will get a permission fault instead.
*/
ftype = VM_PROT_READ;
/* STR instruction ? */
if ((fault_instruction & 0x0c100000) == 0x04000000)
ftype |= VM_PROT_WRITE;
/* STM instruction ? */
else if ((fault_instruction & 0x0a100000) == 0x08000000)
ftype |= VM_PROT_WRITE;
/* SWP instruction ? */
else if ((fault_instruction & 0x0fb00ff0) == 0x01000090)
ftype |= VM_PROT_WRITE;
#ifdef PMAP_DEBUG
if (pmap_debug_level >= 0)
1996-10-13 07:05:43 +04:00
printf("fault protection = %d\n", ftype);
#endif
#ifdef DIAGNOSTIC
if (va == 0 && map == kernel_map) {
printf("trap: bad kernel access at %lx\n", va);
goto we_re_toast;
}
#endif /* DIAGNOSTIC */
nss = 0;
if ((caddr_t)va >= vm->vm_maxsaddr
&& (caddr_t)va < (caddr_t)VM_MAXUSER_ADDRESS
&& map != kernel_map) {
nss = clrnd(btoc(USRSTACK-(u_int)va));
if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
rv = KERN_FAILURE;
goto nogo;
}
}
rv = vm_fault(map, va, ftype, FALSE);
if (rv == KERN_SUCCESS) {
if (nss > vm->vm_ssize)
vm->vm_ssize = nss;
if (fault_code == FAULT_TRANS_P)
return;
goto out;
}
nogo:
if (user == 0) {
1996-10-13 07:05:43 +04:00
printf("Failed page fault in kernel\n");
if (pcb->pcb_onfault)
goto copyfault;
printf("vm_fault(%p, %lx, %x, 0) -> %x\n",
map, va, ftype, rv);
goto we_re_toast;
}
report_abort("", fault_status, fault_address, fault_pc);
trapsignal(p, SIGSEGV, TRAP_CODE);
break;
}
case FAULT_TRANS_S: /* Section Translation Fault */
/* Section translation fault - the L1 page table does not exist */
{
register vm_offset_t va;
register struct vmspace *vm = p->p_vmspace;
register vm_map_t map;
int rv;
vm_prot_t ftype;
u_int nss;
va = trunc_page((vm_offset_t)fault_address);
#ifdef PMAP_DEBUG
if (pmap_debug_level >= 0)
printf("section fault page addr=V%08lx\n", 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 == 0 && va >= KERNEL_BASE)
map = kernel_map;
else
map = &vm->vm_map;
/* We are mapping a page table so this must be kernel r/w */
ftype = VM_PROT_READ | VM_PROT_WRITE;
#ifdef DIAGNOSTIC
if (va == 0 && map == kernel_map) {
printf("trap: bad kernel access at %lx\n", va);
goto we_re_toast;
}
#endif /* DIAGNOSTIC */
nss = 0;
if ((caddr_t)va >= vm->vm_maxsaddr
&& (caddr_t)va < (caddr_t)VM_MAXUSER_ADDRESS
&& map != kernel_map) {
nss = clrnd(btoc(USRSTACK-(u_int)va));
if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
printf("Stack limit exceeded %x %x\n",
nss, (u_int)btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur));
rv = KERN_FAILURE;
goto nogo1;
}
}
/* check if page table is mapped, if not, fault it first */
#ifdef PMAP_DEBUG
if (pmap_debug_level >= 0)
printf("faulting in page %08lx\n", va);
#endif
ftype = VM_PROT_READ;
rv = vm_fault(map, va, ftype, FALSE);
if (rv == KERN_SUCCESS) {
if (nss > vm->vm_ssize)
vm->vm_ssize = nss;
if (fault_code == FAULT_TRANS_S)
return;
goto out;
}
nogo1:
report_abort("", fault_status, fault_address, fault_pc);
if (user == 0) {
1996-10-13 07:05:43 +04:00
printf("Section fault in SVC mode\n");
if (pcb->pcb_onfault)
goto copyfault;
printf("vm_fault(%p, %lx, %x, 0) -> %x\n",
map, va, ftype, rv);
goto we_re_toast;
}
trapsignal(p, SIGSEGV, TRAP_CODE);
break;
}
}
out:
/* Call userret() if it was a USR mode fault */
if (user)
userret(p, frame->tf_pc, sticks);
}
/*
* void prefetch_abort_handler(trapframe_t *frame)
*
* Abort handler called when instruction execution occurs at
* a non existant 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;
u_quad_t sticks;
pt_entry_t *pte;
int error;
#ifdef DIAGNOSTIC
/* Paranoia: We should always be in SVC32 mode at this point */
if ((GetCPSR() & PSR_MODE) != PSR_SVC32_MODE) {
panic("Fault handler not in SVC mode\n");
}
#endif /* DIAGNOSTIC */
/*
* 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);
/* Update vmmeter statistics */
cnt.v_trap++;
/* 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;
1996-10-13 07:05:43 +04:00
printf("Prefetch about with curproc == 0\n");
}
#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 DIAGNOSTIC
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 /* DIAGNOSTIC */
/* Was the prefectch abort from USR32 mode ? */
if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
sticks = p->p_sticks;
p->p_md.md_regs = frame;
} else {
/*
* All the kernel code pages are loaded at boot time
* and do not get paged
*/
1996-10-13 07:05:43 +04:00
printf("Prefetch address = %08x\n", frame->tf_pc);
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) {
if (verbose_faults)
printf("prefetch: pc (%08x) not in user process space\n",
fault_pc);
trapsignal(p, SIGSEGV, fault_pc);
userret(p, frame->tf_pc, sticks);
return;
}
/* Is the page already mapped ? */
/* This is debugging for rev K SA110 silicon */
pte = pmap_pte(p->p_vmspace->vm_map.pmap, (vm_offset_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) {
if (verbose_faults)
printf("prefetch: faultin failed for address %08x\n",
fault_pc);
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,
(vm_offset_t)fault_pc);
if (pte)
printf(" pte=%p *pte=%08x\n", pte, *pte);
else
printf("\n");
}
#endif /* PMAP_DEBUG */
#endif /* DIAGNOSTIC */
}
userret(p, frame->tf_pc, sticks);
}
/* End of fault.c */