Index: sys/amd64/amd64/trap.c =================================================================== --- sys/amd64/amd64/trap.c +++ sys/amd64/amd64/trap.c @@ -111,7 +111,7 @@ void trap_check(struct trapframe *frame); void dblfault_handler(struct trapframe *frame); -static int trap_pfault(struct trapframe *, int); +static int trap_pfault(struct trapframe *, bool, int *, int *); static void trap_fatal(struct trapframe *, vm_offset_t); #ifdef KDTRACE_HOOKS static bool trap_user_dtrace(struct trapframe *, @@ -155,10 +155,6 @@ [T_DTRACE_RET] = "DTrace pid return trap", }; -static int prot_fault_translation; -SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RWTUN, - &prot_fault_translation, 0, - "Select signal to deliver on protection fault"); static int uprintf_signal; SYSCTL_INT(_machdep, OID_AUTO, uprintf_signal, CTLFLAG_RWTUN, &uprintf_signal, 0, @@ -352,40 +348,11 @@ return; addr = frame->tf_addr; - signo = trap_pfault(frame, TRUE); + trap_pfault(frame, true, &signo, &ucode); if (signo == -1) return; if (signo == 0) goto userret; - if (signo == SIGSEGV) { - ucode = SEGV_MAPERR; - } else if (prot_fault_translation == 0) { - /* - * Autodetect. This check also covers - * the images without the ABI-tag ELF - * note. - */ - if (SV_CURPROC_ABI() == SV_ABI_FREEBSD && - p->p_osrel >= P_OSREL_SIGSEGV) { - signo = SIGSEGV; - ucode = SEGV_ACCERR; - } else { - signo = SIGBUS; - ucode = T_PAGEFLT; - } - } else if (prot_fault_translation == 1) { - /* - * Always compat mode. - */ - signo = SIGBUS; - ucode = T_PAGEFLT; - } else { - /* - * Always SIGSEGV mode. - */ - signo = SIGSEGV; - ucode = SEGV_ACCERR; - } break; case T_DIVIDE: /* integer divide fault */ @@ -440,7 +407,7 @@ ("kernel trap doesn't have ucred")); switch (type) { case T_PAGEFLT: /* page fault */ - (void) trap_pfault(frame, FALSE); + (void) trap_pfault(frame, false, NULL, NULL); return; case T_DNA: @@ -713,7 +680,7 @@ } static int -trap_pfault(struct trapframe *frame, int usermode) +trap_pfault(struct trapframe *frame, bool usermode, int *signo, int *ucode) { struct thread *td; struct proc *p; @@ -776,8 +743,11 @@ /* * Don't allow user-mode faults in kernel address space. */ - if (usermode) - return (SIGSEGV); + if (usermode) { + *signo = SIGSEGV; + *ucode = SEGV_ACCERR; + return (1); + } map = kernel_map; } else { @@ -843,7 +813,7 @@ ftype = VM_PROT_READ; /* Fault in the page. */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); + rv = vm_fault_trap(map, va, ftype, VM_FAULT_NORMAL, signo, ucode); if (rv == KERN_SUCCESS) { #ifdef HWPMC_HOOKS if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { @@ -858,17 +828,17 @@ #endif return (0); } + after_vmfault: - if (!usermode) { - if (td->td_intr_nesting_level == 0 && - curpcb->pcb_onfault != NULL) { - frame->tf_rip = (long)curpcb->pcb_onfault; - return (0); - } - trap_fatal(frame, eva); - return (-1); + if (usermode) + return (1); + if (td->td_intr_nesting_level == 0 && + curpcb->pcb_onfault != NULL) { + frame->tf_rip = (long)curpcb->pcb_onfault; + return (0); } - return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); + trap_fatal(frame, eva); + return (-1); } static void Index: sys/amd64/vmm/vmm.c =================================================================== --- sys/amd64/vmm/vmm.c +++ sys/amd64/vmm/vmm.c @@ -1413,7 +1413,8 @@ } map = &vm->vmspace->vm_map; - rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL); + rv = vm_fault_hold(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL, + NULL); VCPU_CTR3(vm, vcpuid, "vm_handle_paging rv = %d, gpa = %#lx, " "ftype = %d", rv, vme->u.paging.gpa, ftype); Index: sys/i386/i386/trap.c =================================================================== --- sys/i386/i386/trap.c +++ sys/i386/i386/trap.c @@ -114,7 +114,7 @@ void trap(struct trapframe *frame); void syscall(struct trapframe *frame); -static int trap_pfault(struct trapframe *, int, vm_offset_t); +static int trap_pfault(struct trapframe *, int, vm_offset_t, int *, int *); static void trap_fatal(struct trapframe *, vm_offset_t); #ifdef KDTRACE_HOOKS static bool trap_user_dtrace(struct trapframe *, @@ -181,9 +181,6 @@ int has_f00f_bug = 0; /* Initialized so that it can be patched. */ #endif -static int prot_fault_translation = 0; -SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW, - &prot_fault_translation, 0, "Select signal to deliver on protection fault"); static int uprintf_signal; SYSCTL_INT(_machdep, OID_AUTO, uprintf_signal, CTLFLAG_RW, &uprintf_signal, 0, @@ -395,7 +392,8 @@ break; case T_PAGEFLT: /* page fault */ - signo = trap_pfault(frame, TRUE, eva); + addr = eva; + trap_pfault(frame, TRUE, eva, &signo, &ucode); #if defined(I586_CPU) && !defined(NO_F00F_HACK) if (signo == -2) { /* @@ -415,37 +413,6 @@ return; if (signo == 0) goto user; - - if (signo == SIGSEGV) - ucode = SEGV_MAPERR; - else if (prot_fault_translation == 0) { - /* - * Autodetect. This check also covers - * the images without the ABI-tag ELF - * note. - */ - if (SV_CURPROC_ABI() == SV_ABI_FREEBSD && - p->p_osrel >= P_OSREL_SIGSEGV) { - signo = SIGSEGV; - ucode = SEGV_ACCERR; - } else { - signo = SIGBUS; - ucode = T_PAGEFLT; - } - } else if (prot_fault_translation == 1) { - /* - * Always compat mode. - */ - signo = SIGBUS; - ucode = T_PAGEFLT; - } else { - /* - * Always SIGSEGV mode. - */ - signo = SIGSEGV; - ucode = SEGV_ACCERR; - } - addr = eva; break; case T_DIVIDE: /* integer divide fault */ @@ -517,7 +484,7 @@ ("kernel trap doesn't have ucred")); switch (type) { case T_PAGEFLT: /* page fault */ - (void) trap_pfault(frame, FALSE, eva); + (void) trap_pfault(frame, FALSE, eva, NULL, NULL); return; case T_DNA: @@ -770,7 +737,8 @@ } static int -trap_pfault(struct trapframe *frame, int usermode, vm_offset_t eva) +trap_pfault(struct trapframe *frame, int usermode, vm_offset_t eva, + int *signo, int *ucode) { struct thread *td; struct proc *p; @@ -878,7 +846,7 @@ ftype = VM_PROT_READ; /* Fault in the page. */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); + rv = vm_fault_trap(map, va, ftype, VM_FAULT_NORMAL, signo, ucode); if (rv == KERN_SUCCESS) { #ifdef HWPMC_HOOKS if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { @@ -893,16 +861,15 @@ #endif return (0); } - if (!usermode) { - if (td->td_intr_nesting_level == 0 && - curpcb->pcb_onfault != NULL) { - frame->tf_eip = (int)curpcb->pcb_onfault; - return (0); - } - trap_fatal(frame, eva); - return (-1); + if (usermode) + return (1); + if (td->td_intr_nesting_level == 0 && + curpcb->pcb_onfault != NULL) { + frame->tf_eip = (int)curpcb->pcb_onfault; + return (0); } - return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); + trap_fatal(frame, eva); + return (-1); } static void Index: sys/vm/vm_extern.h =================================================================== --- sys/vm/vm_extern.h +++ sys/vm/vm_extern.h @@ -85,7 +85,8 @@ int kernacc(void *, int, int); int useracc(void *, int, int); -int vm_fault(vm_map_t, vm_offset_t, vm_prot_t, int); +int vm_fault_trap(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, + int fault_flags, int *signo, int *ucode); void vm_fault_copy_entry(vm_map_t, vm_map_t, vm_map_entry_t, vm_map_entry_t, vm_ooffset_t *); int vm_fault_disable_pagefaults(void); Index: sys/vm/vm_fault.c =================================================================== --- sys/vm/vm_fault.c +++ sys/vm/vm_fault.c @@ -89,7 +89,9 @@ #include #include #include +#include #include +#include #include #include #ifdef KTRACE @@ -529,8 +531,19 @@ return (KERN_SUCCESS); } +static int prot_fault_translation; +SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RWTUN, + &prot_fault_translation, 0, + "Select signal to deliver on protection fault"); + +/* compat definition to keep common code for signal translation */ +#define UCODE_PAGEFLT 12 +#ifdef T_PAGEFLT +_Static_assert(UCODE_PAGEFLT == T_PAGEFLT, "T_PAGEFLT"); +#endif + /* - * vm_fault: + * vm_fault_trap: * * Handle a page fault occurring at the given address, * requiring the given permissions, in the map specified. @@ -547,8 +560,8 @@ * Caller may hold no locks. */ int -vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, - int fault_flags) +vm_fault_trap(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, + int fault_flags, int *signo, int *ucode) { struct thread *td; int result; @@ -562,10 +575,49 @@ #endif result = vm_fault_hold(map, trunc_page(vaddr), fault_type, fault_flags, NULL); + KASSERT(result == KERN_SUCCESS || result == KERN_FAILURE || + result == KERN_INVALID_ADDRESS || + result == KERN_RESOURCE_SHORTAGE || + result == KERN_PROTECTION_FAILURE, + ("Unknown Mach error %d from vm_fault_hold()", result)); #ifdef KTRACE if (map != kernel_map && KTRPOINT(td, KTR_FAULTEND)) ktrfaultend(result); #endif + if (result != KERN_SUCCESS && map != kernel_map) { + if (result == KERN_FAILURE) { + *signo = SIGSEGV; + *ucode = SEGV_MAPERR; + } else if (result == KERN_RESOURCE_SHORTAGE) { + *signo = SIGBUS; + *ucode = BUS_ADRERR; /* XXX any better choice ? */ + } else if (result == KERN_INVALID_ADDRESS) { + *signo = SIGBUS; + *ucode = BUS_OBJERR; + } else if (prot_fault_translation == 0) { + /* + * Autodetect. This check also covers + * the images without the ABI-tag ELF + * note. + */ + if (SV_CURPROC_ABI() == SV_ABI_FREEBSD && + curproc->p_osrel >= P_OSREL_SIGSEGV) { + *signo = SIGSEGV; + *ucode = SEGV_ACCERR; + } else { + *signo = SIGBUS; + *ucode = UCODE_PAGEFLT; + } + } else if (prot_fault_translation == 1) { + /* Always compat mode. */ + *signo = SIGBUS; + *ucode = UCODE_PAGEFLT; + } else { + /* Always SIGSEGV mode. */ + *signo = SIGSEGV; + *ucode = SEGV_ACCERR; + } + } return (result); } @@ -787,7 +839,7 @@ fs.object == fs.first_object) { if (fs.pindex >= fs.object->size) { unlock_and_deallocate(&fs); - return (KERN_PROTECTION_FAILURE); + return (KERN_INVALID_ADDRESS); } if (fs.object == fs.first_object && Index: sys/vm/vm_map.c =================================================================== --- sys/vm/vm_map.c +++ sys/vm/vm_map.c @@ -3201,8 +3201,9 @@ * Simulate a fault to get the page and enter * it into the physical map. */ - if ((rv = vm_fault(map, faddr, VM_PROT_NONE, - VM_FAULT_WIRE)) != KERN_SUCCESS) + if ((rv = vm_fault_hold(map, faddr, + VM_PROT_NONE, VM_FAULT_WIRE, NULL)) != + KERN_SUCCESS) break; } while ((faddr += PAGE_SIZE) < saved_end); vm_map_lock(map);