1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/arch/m68k/mm/fault.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 1995 Hamish Macdonald 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds #include <linux/mman.h> 91da177e4SLinus Torvalds #include <linux/mm.h> 101da177e4SLinus Torvalds #include <linux/kernel.h> 111da177e4SLinus Torvalds #include <linux/ptrace.h> 121da177e4SLinus Torvalds #include <linux/interrupt.h> 131da177e4SLinus Torvalds #include <linux/module.h> 1470ffdb93SDavid Hildenbrand #include <linux/uaccess.h> 15e1c17f62SPeter Xu #include <linux/perf_event.h> 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds #include <asm/setup.h> 181da177e4SLinus Torvalds #include <asm/traps.h> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds extern void die_if_kernel(char *, struct pt_regs *, long); 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds int send_fault_sig(struct pt_regs *regs) 231da177e4SLinus Torvalds { 243c67075dSEric W. Biederman int signo, si_code; 253c67075dSEric W. Biederman void __user *addr; 261da177e4SLinus Torvalds 273c67075dSEric W. Biederman signo = current->thread.signo; 283c67075dSEric W. Biederman si_code = current->thread.code; 293c67075dSEric W. Biederman addr = (void __user *)current->thread.faddr; 303c67075dSEric W. Biederman pr_debug("send_fault_sig: %p,%d,%d\n", addr, signo, si_code); 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds if (user_mode(regs)) { 332e1661d2SEric W. Biederman force_sig_fault(signo, si_code, addr); 341da177e4SLinus Torvalds } else { 3568acfdcbSAl Viro if (fixup_exception(regs)) 361da177e4SLinus Torvalds return -1; 371da177e4SLinus Torvalds 383c67075dSEric W. Biederman //if (signo == SIGBUS) 392e1661d2SEric W. Biederman // force_sig_fault(si_signo, si_code, addr); 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds /* 421da177e4SLinus Torvalds * Oops. The kernel tried to access some bad page. We'll have to 431da177e4SLinus Torvalds * terminate things with extreme prejudice. 441da177e4SLinus Torvalds */ 453c67075dSEric W. Biederman if ((unsigned long)addr < PAGE_SIZE) 468e398f63SGeert Uytterhoeven pr_alert("Unable to handle kernel NULL pointer dereference"); 471da177e4SLinus Torvalds else 488e398f63SGeert Uytterhoeven pr_alert("Unable to handle kernel access"); 493c67075dSEric W. Biederman pr_cont(" at virtual address %p\n", addr); 501da177e4SLinus Torvalds die_if_kernel("Oops", regs, 0 /*error_code*/); 510e25498fSEric W. Biederman make_task_dead(SIGKILL); 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds return 1; 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* 581da177e4SLinus Torvalds * This routine handles page faults. It determines the problem, and 591da177e4SLinus Torvalds * then passes it off to one of the appropriate routines. 601da177e4SLinus Torvalds * 611da177e4SLinus Torvalds * error_code: 621da177e4SLinus Torvalds * bit 0 == 0 means no page found, 1 means protection fault 631da177e4SLinus Torvalds * bit 1 == 0 means read, 1 means write 641da177e4SLinus Torvalds * 651da177e4SLinus Torvalds * If this routine detects a bad access, it returns 1, otherwise it 661da177e4SLinus Torvalds * returns 0. 671da177e4SLinus Torvalds */ 681da177e4SLinus Torvalds int do_page_fault(struct pt_regs *regs, unsigned long address, 691da177e4SLinus Torvalds unsigned long error_code) 701da177e4SLinus Torvalds { 711da177e4SLinus Torvalds struct mm_struct *mm = current->mm; 721da177e4SLinus Torvalds struct vm_area_struct * vma; 7350a7ca3cSSouptick Joarder vm_fault_t fault; 74dde16072SPeter Xu unsigned int flags = FAULT_FLAG_DEFAULT; 751da177e4SLinus Torvalds 768e398f63SGeert Uytterhoeven pr_debug("do page fault:\nregs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n", 774e25c0e9SGeert Uytterhoeven regs->sr, regs->pc, address, error_code, mm ? mm->pgd : NULL); 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds /* 801da177e4SLinus Torvalds * If we're in an interrupt or have no user 811da177e4SLinus Torvalds * context, we must not take the fault.. 821da177e4SLinus Torvalds */ 8370ffdb93SDavid Hildenbrand if (faulthandler_disabled() || !mm) 841da177e4SLinus Torvalds goto no_context; 851da177e4SLinus Torvalds 86759496baSJohannes Weiner if (user_mode(regs)) 87759496baSJohannes Weiner flags |= FAULT_FLAG_USER; 88e1c17f62SPeter Xu 89e1c17f62SPeter Xu perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); 90b637a6b1SKautuk Consul retry: 91d8ed45c5SMichel Lespinasse mmap_read_lock(mm); 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds vma = find_vma(mm, address); 941da177e4SLinus Torvalds if (!vma) 951da177e4SLinus Torvalds goto map_err; 961da177e4SLinus Torvalds if (vma->vm_start <= address) 971da177e4SLinus Torvalds goto good_area; 981da177e4SLinus Torvalds if (!(vma->vm_flags & VM_GROWSDOWN)) 991da177e4SLinus Torvalds goto map_err; 1001da177e4SLinus Torvalds if (user_mode(regs)) { 1011da177e4SLinus Torvalds /* Accessing the stack below usp is always a bug. The 1021da177e4SLinus Torvalds "+ 256" is there due to some instructions doing 1031da177e4SLinus Torvalds pre-decrement on the stack and that doesn't show up 1041da177e4SLinus Torvalds until later. */ 1051da177e4SLinus Torvalds if (address + 256 < rdusp()) 1061da177e4SLinus Torvalds goto map_err; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds if (expand_stack(vma, address)) 1091da177e4SLinus Torvalds goto map_err; 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds /* 1121da177e4SLinus Torvalds * Ok, we have a good vm_area for this memory access, so 1131da177e4SLinus Torvalds * we can handle it.. 1141da177e4SLinus Torvalds */ 1151da177e4SLinus Torvalds good_area: 1168e398f63SGeert Uytterhoeven pr_debug("do_page_fault: good_area\n"); 1171da177e4SLinus Torvalds switch (error_code & 3) { 1181da177e4SLinus Torvalds default: /* 3: write, present */ 119df561f66SGustavo A. R. Silva fallthrough; 1201da177e4SLinus Torvalds case 2: /* write, not present */ 1211da177e4SLinus Torvalds if (!(vma->vm_flags & VM_WRITE)) 1221da177e4SLinus Torvalds goto acc_err; 123b637a6b1SKautuk Consul flags |= FAULT_FLAG_WRITE; 1241da177e4SLinus Torvalds break; 1251da177e4SLinus Torvalds case 1: /* read, present */ 1261da177e4SLinus Torvalds goto acc_err; 1271da177e4SLinus Torvalds case 0: /* read, not present */ 1285093c587SAnshuman Khandual if (unlikely(!vma_is_accessible(vma))) 1291da177e4SLinus Torvalds goto acc_err; 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds /* 1331da177e4SLinus Torvalds * If for any reason at all we couldn't handle the fault, 1341da177e4SLinus Torvalds * make sure we exit gracefully rather than endlessly redo 1351da177e4SLinus Torvalds * the fault. 1361da177e4SLinus Torvalds */ 1371da177e4SLinus Torvalds 138e1c17f62SPeter Xu fault = handle_mm_fault(vma, address, flags, regs); 13950a7ca3cSSouptick Joarder pr_debug("handle_mm_fault returns %x\n", fault); 140b637a6b1SKautuk Consul 141*bd75497aSAl Viro if (fault_signal_pending(fault, regs)) { 142*bd75497aSAl Viro if (!user_mode(regs)) 143*bd75497aSAl Viro goto no_context; 144b637a6b1SKautuk Consul return 0; 145*bd75497aSAl Viro } 146b637a6b1SKautuk Consul 147d9272525SPeter Xu /* The fault is fully completed (including releasing mmap lock) */ 148d9272525SPeter Xu if (fault & VM_FAULT_COMPLETED) 149d9272525SPeter Xu return 0; 150d9272525SPeter Xu 15183c54070SNick Piggin if (unlikely(fault & VM_FAULT_ERROR)) { 15283c54070SNick Piggin if (fault & VM_FAULT_OOM) 1531da177e4SLinus Torvalds goto out_of_memory; 15433692f27SLinus Torvalds else if (fault & VM_FAULT_SIGSEGV) 15533692f27SLinus Torvalds goto map_err; 15683c54070SNick Piggin else if (fault & VM_FAULT_SIGBUS) 15783c54070SNick Piggin goto bus_err; 15883c54070SNick Piggin BUG(); 1591da177e4SLinus Torvalds } 160b637a6b1SKautuk Consul 161b637a6b1SKautuk Consul if (fault & VM_FAULT_RETRY) { 16245cac65bSShaohua Li flags |= FAULT_FLAG_TRIED; 163b637a6b1SKautuk Consul 164b637a6b1SKautuk Consul /* 1653e4e28c5SMichel Lespinasse * No need to mmap_read_unlock(mm) as we would 166b637a6b1SKautuk Consul * have already released it in __lock_page_or_retry 167b637a6b1SKautuk Consul * in mm/filemap.c. 168b637a6b1SKautuk Consul */ 169b637a6b1SKautuk Consul 170b637a6b1SKautuk Consul goto retry; 171b637a6b1SKautuk Consul } 1721da177e4SLinus Torvalds 173d8ed45c5SMichel Lespinasse mmap_read_unlock(mm); 1741da177e4SLinus Torvalds return 0; 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds /* 1771da177e4SLinus Torvalds * We ran out of memory, or some other thing happened to us that made 1781da177e4SLinus Torvalds * us unable to handle the page fault gracefully. 1791da177e4SLinus Torvalds */ 1801da177e4SLinus Torvalds out_of_memory: 181d8ed45c5SMichel Lespinasse mmap_read_unlock(mm); 182adbf6e69SNick Piggin if (!user_mode(regs)) 183adbf6e69SNick Piggin goto no_context; 184adbf6e69SNick Piggin pagefault_out_of_memory(); 185adbf6e69SNick Piggin return 0; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds no_context: 1881da177e4SLinus Torvalds current->thread.signo = SIGBUS; 1891da177e4SLinus Torvalds current->thread.faddr = address; 1901da177e4SLinus Torvalds return send_fault_sig(regs); 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds bus_err: 1931da177e4SLinus Torvalds current->thread.signo = SIGBUS; 1941da177e4SLinus Torvalds current->thread.code = BUS_ADRERR; 1951da177e4SLinus Torvalds current->thread.faddr = address; 1961da177e4SLinus Torvalds goto send_sig; 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds map_err: 1991da177e4SLinus Torvalds current->thread.signo = SIGSEGV; 2001da177e4SLinus Torvalds current->thread.code = SEGV_MAPERR; 2011da177e4SLinus Torvalds current->thread.faddr = address; 2021da177e4SLinus Torvalds goto send_sig; 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds acc_err: 2051da177e4SLinus Torvalds current->thread.signo = SIGSEGV; 2061da177e4SLinus Torvalds current->thread.code = SEGV_ACCERR; 2071da177e4SLinus Torvalds current->thread.faddr = address; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds send_sig: 210d8ed45c5SMichel Lespinasse mmap_read_unlock(mm); 2111da177e4SLinus Torvalds return send_fault_sig(regs); 2121da177e4SLinus Torvalds } 213