/* Are we prepared to handle this kernel fault? */ if (fixup_exception(regs)) return;
if (kfence_handle_page_fault(address, write, regs)) return;
/* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice.
*/
bust_spinlocks(1);
pr_alert("CPU %d Unable to handle kernel paging request at " "virtual address %0*lx, era == %0*lx, ra == %0*lx\n",
raw_smp_processor_id(), field, address, field, regs->csr_era,
field, regs->regs[1]);
die("Oops", regs);
}
staticvoid __kprobes do_out_of_memory(struct pt_regs *regs, unsignedlong write, unsignedlong address)
{ /* * We ran out of memory, call the OOM killer, and return the userspace * (which will retry the fault, or kill us if we got oom-killed).
*/ if (!user_mode(regs)) {
no_context(regs, write, address); return;
}
pagefault_out_of_memory();
}
staticvoid __kprobes do_sigbus(struct pt_regs *regs, unsignedlong write, unsignedlong address, int si_code)
{ /* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) {
no_context(regs, write, address); return;
}
/* * Send a sigbus, regardless of whether we were in kernel * or user mode.
*/
current->thread.csr_badvaddr = address;
current->thread.trap_nr = read_csr_excode();
force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address);
}
/* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) {
no_context(regs, write, address); return;
}
/* User mode accesses just cause a SIGSEGV */
current->thread.csr_badvaddr = address; if (!write)
current->thread.error_code = 1; else
current->thread.error_code = 2;
current->thread.trap_nr = read_csr_excode();
/* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate * routines.
*/ staticvoid __kprobes __do_page_fault(struct pt_regs *regs, unsignedlong write, unsignedlong address)
{ int si_code = SEGV_MAPERR; unsignedint flags = FAULT_FLAG_DEFAULT; struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; struct vm_area_struct *vma = NULL;
vm_fault_t fault;
if (kprobe_page_fault(regs, current->thread.trap_nr)) return;
/* * We fault-in kernel-space virtual memory on-demand. The * 'reference' page table is init_mm.pgd. * * NOTE! We MUST NOT take any locks for this case. We may * be in an interrupt or a critical region, and should * only copy the information from the master page table, * nothing more.
*/ if (address & __UA_LIMIT) { if (!user_mode(regs))
no_context(regs, write, address); else
do_sigsegv(regs, write, address, si_code); return;
}
/* * If we're in an interrupt or have no user * context, we must not take the fault..
*/ if (faulthandler_disabled() || !mm) {
do_sigsegv(regs, write, address, si_code); return;
}
/* * Something tried to access memory that isn't in our memory map.. * Fix it, but check if it's kernel or user first..
*/
bad_area:
mmap_read_unlock(mm);
bad_area_nosemaphore:
do_sigsegv(regs, write, address, si_code); return;
/* * Ok, we have a good vm_area for this memory access, so * we can handle it..
*/
good_area:
si_code = SEGV_ACCERR;
if (write) {
flags |= FAULT_FLAG_WRITE; if (!(vma->vm_flags & VM_WRITE)) goto bad_area;
} else { if (!(vma->vm_flags & VM_EXEC) && address == exception_era(regs)) goto bad_area; if (!(vma->vm_flags & (VM_READ | VM_WRITE)) && address != exception_era(regs)) goto bad_area;
}
/* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo * the fault.
*/
fault = handle_mm_fault(vma, address, flags, regs);
if (fault_signal_pending(fault, regs)) { if (!user_mode(regs))
no_context(regs, write, address); return;
}
/* The fault is fully completed (including releasing mmap lock) */ if (fault & VM_FAULT_COMPLETED) return;
if (unlikely(fault & VM_FAULT_RETRY)) {
flags |= FAULT_FLAG_TRIED;
/* * No need to mmap_read_unlock(mm) as we would * have already released it in __lock_page_or_retry * in mm/filemap.c.
*/ goto retry;
} if (unlikely(fault & VM_FAULT_ERROR)) {
mmap_read_unlock(mm); if (fault & VM_FAULT_OOM) {
do_out_of_memory(regs, write, address); return;
} elseif (fault & VM_FAULT_SIGSEGV) {
do_sigsegv(regs, write, address, si_code); return;
} elseif (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
do_sigbus(regs, write, address, si_code); return;
}
BUG();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.