Changeset View
Changeset View
Standalone View
Standalone View
head/sys/arm/arm/trap-v4.c
Show First 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | |||||
#include <sys/signalvar.h> | #include <sys/signalvar.h> | ||||
#include <sys/vmmeter.h> | #include <sys/vmmeter.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <vm/vm_kern.h> | #include <vm/vm_kern.h> | ||||
#include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/vm_param.h> | |||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||
#include <machine/frame.h> | #include <machine/frame.h> | ||||
#include <machine/machdep.h> | #include <machine/machdep.h> | ||||
#include <machine/pcb.h> | #include <machine/pcb.h> | ||||
#include <machine/vmparam.h> | |||||
#ifdef KDB | #ifdef KDB | ||||
#include <sys/kdb.h> | #include <sys/kdb.h> | ||||
#endif | #endif | ||||
#ifdef KDTRACE_HOOKS | #ifdef KDTRACE_HOOKS | ||||
#include <sys/dtrace_bsd.h> | #include <sys/dtrace_bsd.h> | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct vm_map *map; | struct vm_map *map; | ||||
struct pcb *pcb; | struct pcb *pcb; | ||||
struct thread *td; | struct thread *td; | ||||
u_int user, far, fsr; | u_int user, far, fsr; | ||||
vm_prot_t ftype; | vm_prot_t ftype; | ||||
void *onfault; | void *onfault; | ||||
vm_offset_t va; | vm_offset_t va; | ||||
int error = 0; | int error = 0, signo, ucode; | ||||
struct ksig ksig; | struct ksig ksig; | ||||
struct proc *p; | struct proc *p; | ||||
if (type == 1) | if (type == 1) | ||||
return (prefetch_abort_handler(tf)); | return (prefetch_abort_handler(tf)); | ||||
/* Grab FAR/FSR before enabling interrupts */ | /* Grab FAR/FSR before enabling interrupts */ | ||||
far = cp15_dfar_get(); | far = cp15_dfar_get(); | ||||
Show All 32 Lines | if (__predict_true(tf->tf_spsr & PSR_F) == 0) | ||||
enable_interrupts(PSR_F); | enable_interrupts(PSR_F); | ||||
} | } | ||||
/* Invoke the appropriate handler, if necessary */ | /* Invoke the appropriate handler, if necessary */ | ||||
if (__predict_false(data_aborts[fsr & FAULT_TYPE_MASK].func != NULL)) { | if (__predict_false(data_aborts[fsr & FAULT_TYPE_MASK].func != NULL)) { | ||||
if ((data_aborts[fsr & FAULT_TYPE_MASK].func)(tf, fsr, far, | if ((data_aborts[fsr & FAULT_TYPE_MASK].func)(tf, fsr, far, | ||||
td, &ksig)) { | td, &ksig)) { | ||||
signo = ksig.signb; | |||||
ucode = ksig.code; | |||||
goto do_trapsignal; | goto do_trapsignal; | ||||
} | } | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* At this point, we're dealing with one of the following data aborts: | * At this point, we're dealing with one of the following data aborts: | ||||
* | * | ||||
Show All 16 Lines | #endif | ||||
* XXX: It would be nice to be able to support Thumb at some point. | * XXX: It would be nice to be able to support Thumb at some point. | ||||
*/ | */ | ||||
if (__predict_false((tf->tf_pc & 3) != 0)) { | if (__predict_false((tf->tf_pc & 3) != 0)) { | ||||
if (user) { | if (user) { | ||||
/* | /* | ||||
* Give the user an illegal instruction signal. | * Give the user an illegal instruction signal. | ||||
*/ | */ | ||||
/* Deliver a SIGILL to the process */ | /* Deliver a SIGILL to the process */ | ||||
ksig.signb = SIGILL; | signo = SIGILL; | ||||
ksig.code = 0; | ucode = 0; | ||||
goto do_trapsignal; | goto do_trapsignal; | ||||
} | } | ||||
/* | /* | ||||
* The kernel never executes Thumb code. | * The kernel never executes Thumb code. | ||||
*/ | */ | ||||
printf("\ndata_abort_fault: Misaligned Kernel-mode " | printf("\ndata_abort_fault: Misaligned Kernel-mode " | ||||
"Program Counter\n"); | "Program Counter\n"); | ||||
Show All 19 Lines | if (__predict_false((tf->tf_spsr & PSR_MODE)==PSR_UND32_MODE)) { | ||||
/* | /* | ||||
* Force exit via userret() | * Force exit via userret() | ||||
* This is necessary as the FPE is an extension to | * This is necessary as the FPE is an extension to | ||||
* userland that actually runs in a priveledged mode | * userland that actually runs in a priveledged mode | ||||
* but uses USR mode permissions for its accesses. | * but uses USR mode permissions for its accesses. | ||||
*/ | */ | ||||
user = 1; | user = 1; | ||||
ksig.signb = SIGSEGV; | signo = SIGSEGV; | ||||
ksig.code = 0; | ucode = 0; | ||||
goto do_trapsignal; | goto do_trapsignal; | ||||
} | } | ||||
} else { | } else { | ||||
map = &td->td_proc->p_vmspace->vm_map; | map = &td->td_proc->p_vmspace->vm_map; | ||||
} | } | ||||
/* | /* | ||||
* We need to know whether the page should be mapped as R or R/W. | * We need to know whether the page should be mapped as R or R/W. | ||||
Show All 33 Lines | #endif | ||||
if (pmap_fault_fixup(vmspace_pmap(td->td_proc->p_vmspace), va, ftype, | if (pmap_fault_fixup(vmspace_pmap(td->td_proc->p_vmspace), va, ftype, | ||||
user)) { | user)) { | ||||
goto out; | goto out; | ||||
} | } | ||||
onfault = pcb->pcb_onfault; | onfault = pcb->pcb_onfault; | ||||
pcb->pcb_onfault = NULL; | pcb->pcb_onfault = NULL; | ||||
error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); | error = vm_fault_trap(map, va, ftype, VM_FAULT_NORMAL, &signo, &ucode); | ||||
pcb->pcb_onfault = onfault; | pcb->pcb_onfault = onfault; | ||||
if (__predict_true(error == 0)) | if (__predict_true(error == KERN_SUCCESS)) | ||||
goto out; | goto out; | ||||
fatal_pagefault: | fatal_pagefault: | ||||
if (user == 0) { | if (user == 0) { | ||||
if (pcb->pcb_onfault) { | if (pcb->pcb_onfault) { | ||||
tf->tf_r0 = error; | tf->tf_r0 = error; | ||||
tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; | tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; | ||||
return; | return; | ||||
} | } | ||||
printf("\nvm_fault(%p, %x, %x, 0) -> %x\n", map, va, ftype, | printf("\nvm_fault(%p, %x, %x, 0) -> %x\n", map, va, ftype, | ||||
error); | error); | ||||
dab_fatal(tf, fsr, far, td, &ksig); | dab_fatal(tf, fsr, far, td, &ksig); | ||||
} | } | ||||
if (error == ENOMEM) { | |||||
printf("VM: pid %d (%s), uid %d killed: " | |||||
"out of swap\n", td->td_proc->p_pid, td->td_name, | |||||
(td->td_proc->p_ucred) ? | |||||
td->td_proc->p_ucred->cr_uid : -1); | |||||
ksig.signb = SIGKILL; | |||||
} else { | |||||
ksig.signb = SIGSEGV; | |||||
} | |||||
ksig.code = 0; | |||||
do_trapsignal: | do_trapsignal: | ||||
call_trapsignal(td, ksig.signb, ksig.code); | call_trapsignal(td, signo, ucode); | ||||
out: | out: | ||||
/* If returning to user mode, make sure to invoke userret() */ | /* If returning to user mode, make sure to invoke userret() */ | ||||
if (user) | if (user) | ||||
userret(td, tf); | userret(td, tf); | ||||
} | } | ||||
/* | /* | ||||
* dab_fatal() handles the following data aborts: | * dab_fatal() handles the following data aborts: | ||||
▲ Show 20 Lines • Show All 217 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static void | static void | ||||
prefetch_abort_handler(struct trapframe *tf) | prefetch_abort_handler(struct trapframe *tf) | ||||
{ | { | ||||
struct thread *td; | struct thread *td; | ||||
struct proc * p; | struct proc * p; | ||||
struct vm_map *map; | struct vm_map *map; | ||||
vm_offset_t fault_pc, va; | vm_offset_t fault_pc, va; | ||||
int error = 0; | int error = 0, signo, ucode; | ||||
struct ksig ksig; | struct ksig ksig; | ||||
#if 0 | #if 0 | ||||
/* Update vmmeter statistics */ | /* Update vmmeter statistics */ | ||||
uvmexp.traps++; | uvmexp.traps++; | ||||
#endif | #endif | ||||
#if 0 | #if 0 | ||||
printf("prefetch abort handler: %p %p\n", (void*)tf->tf_pc, | printf("prefetch abort handler: %p %p\n", (void*)tf->tf_pc, | ||||
(void*)tf->tf_usr_lr); | (void*)tf->tf_usr_lr); | ||||
#endif | #endif | ||||
Show All 19 Lines | #endif | ||||
if (__predict_false(!TRAP_USERMODE(tf))) | if (__predict_false(!TRAP_USERMODE(tf))) | ||||
dab_fatal(tf, 0, tf->tf_pc, NULL, &ksig); | dab_fatal(tf, 0, tf->tf_pc, NULL, &ksig); | ||||
td->td_pticks = 0; | td->td_pticks = 0; | ||||
/* Ok validate the address, can only execute in USER space */ | /* Ok validate the address, can only execute in USER space */ | ||||
if (__predict_false(fault_pc >= VM_MAXUSER_ADDRESS || | if (__predict_false(fault_pc >= VM_MAXUSER_ADDRESS || | ||||
(fault_pc < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW))) { | (fault_pc < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW))) { | ||||
ksig.signb = SIGSEGV; | signo = SIGSEGV; | ||||
ksig.code = 0; | ucode = 0; | ||||
goto do_trapsignal; | goto do_trapsignal; | ||||
} | } | ||||
map = &td->td_proc->p_vmspace->vm_map; | map = &td->td_proc->p_vmspace->vm_map; | ||||
va = trunc_page(fault_pc); | va = trunc_page(fault_pc); | ||||
/* | /* | ||||
* See if the pmap can handle this fault on its own... | * See if the pmap can handle this fault on its own... | ||||
*/ | */ | ||||
#ifdef DEBUG | #ifdef DEBUG | ||||
last_fault_code = -1; | last_fault_code = -1; | ||||
#endif | #endif | ||||
if (pmap_fault_fixup(map->pmap, va, VM_PROT_READ, 1)) | if (pmap_fault_fixup(map->pmap, va, VM_PROT_READ, 1)) | ||||
goto out; | goto out; | ||||
error = vm_fault(map, va, VM_PROT_READ | VM_PROT_EXECUTE, | error = vm_fault_trap(map, va, VM_PROT_READ | VM_PROT_EXECUTE, | ||||
VM_FAULT_NORMAL); | VM_FAULT_NORMAL, &signo, &ucode); | ||||
if (__predict_true(error == 0)) | if (__predict_true(error == KERN_SUCCESS)) | ||||
goto out; | goto out; | ||||
if (error == ENOMEM) { | |||||
printf("VM: pid %d (%s), uid %d killed: " | |||||
"out of swap\n", td->td_proc->p_pid, td->td_name, | |||||
(td->td_proc->p_ucred) ? | |||||
td->td_proc->p_ucred->cr_uid : -1); | |||||
ksig.signb = SIGKILL; | |||||
} else { | |||||
ksig.signb = SIGSEGV; | |||||
} | |||||
ksig.code = 0; | |||||
do_trapsignal: | do_trapsignal: | ||||
call_trapsignal(td, ksig.signb, ksig.code); | call_trapsignal(td, signo, ucode); | ||||
out: | out: | ||||
userret(td, tf); | userret(td, tf); | ||||
} | } | ||||
extern int badaddr_read_1(const uint8_t *, uint8_t *); | extern int badaddr_read_1(const uint8_t *, uint8_t *); | ||||
extern int badaddr_read_2(const uint16_t *, uint16_t *); | extern int badaddr_read_2(const uint16_t *, uint16_t *); | ||||
▲ Show 20 Lines • Show All 45 Lines • Show Last 20 Lines |