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
send_fault_sig(struct pt_regs * regs)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 */
do_page_fault(struct pt_regs * regs,unsigned long address,unsigned long error_code)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 }
108*8d7071afSLinus Torvalds vma = expand_stack(mm, address);
109*8d7071afSLinus Torvalds if (!vma)
110*8d7071afSLinus Torvalds goto map_err_nosemaphore;
1111da177e4SLinus Torvalds
1121da177e4SLinus Torvalds /*
1131da177e4SLinus Torvalds * Ok, we have a good vm_area for this memory access, so
1141da177e4SLinus Torvalds * we can handle it..
1151da177e4SLinus Torvalds */
1161da177e4SLinus Torvalds good_area:
1178e398f63SGeert Uytterhoeven pr_debug("do_page_fault: good_area\n");
1181da177e4SLinus Torvalds switch (error_code & 3) {
1191da177e4SLinus Torvalds default: /* 3: write, present */
120df561f66SGustavo A. R. Silva fallthrough;
1211da177e4SLinus Torvalds case 2: /* write, not present */
1221da177e4SLinus Torvalds if (!(vma->vm_flags & VM_WRITE))
1231da177e4SLinus Torvalds goto acc_err;
124b637a6b1SKautuk Consul flags |= FAULT_FLAG_WRITE;
1251da177e4SLinus Torvalds break;
1261da177e4SLinus Torvalds case 1: /* read, present */
1271da177e4SLinus Torvalds goto acc_err;
1281da177e4SLinus Torvalds case 0: /* read, not present */
1295093c587SAnshuman Khandual if (unlikely(!vma_is_accessible(vma)))
1301da177e4SLinus Torvalds goto acc_err;
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds /*
1341da177e4SLinus Torvalds * If for any reason at all we couldn't handle the fault,
1351da177e4SLinus Torvalds * make sure we exit gracefully rather than endlessly redo
1361da177e4SLinus Torvalds * the fault.
1371da177e4SLinus Torvalds */
1381da177e4SLinus Torvalds
139e1c17f62SPeter Xu fault = handle_mm_fault(vma, address, flags, regs);
14050a7ca3cSSouptick Joarder pr_debug("handle_mm_fault returns %x\n", fault);
141b637a6b1SKautuk Consul
142bd75497aSAl Viro if (fault_signal_pending(fault, regs)) {
143bd75497aSAl Viro if (!user_mode(regs))
144bd75497aSAl Viro goto no_context;
145b637a6b1SKautuk Consul return 0;
146bd75497aSAl Viro }
147b637a6b1SKautuk Consul
148d9272525SPeter Xu /* The fault is fully completed (including releasing mmap lock) */
149d9272525SPeter Xu if (fault & VM_FAULT_COMPLETED)
150d9272525SPeter Xu return 0;
151d9272525SPeter Xu
15283c54070SNick Piggin if (unlikely(fault & VM_FAULT_ERROR)) {
15383c54070SNick Piggin if (fault & VM_FAULT_OOM)
1541da177e4SLinus Torvalds goto out_of_memory;
15533692f27SLinus Torvalds else if (fault & VM_FAULT_SIGSEGV)
15633692f27SLinus Torvalds goto map_err;
15783c54070SNick Piggin else if (fault & VM_FAULT_SIGBUS)
15883c54070SNick Piggin goto bus_err;
15983c54070SNick Piggin BUG();
1601da177e4SLinus Torvalds }
161b637a6b1SKautuk Consul
162b637a6b1SKautuk Consul if (fault & VM_FAULT_RETRY) {
16345cac65bSShaohua Li flags |= FAULT_FLAG_TRIED;
164b637a6b1SKautuk Consul
165b637a6b1SKautuk Consul /*
1663e4e28c5SMichel Lespinasse * No need to mmap_read_unlock(mm) as we would
167b637a6b1SKautuk Consul * have already released it in __lock_page_or_retry
168b637a6b1SKautuk Consul * in mm/filemap.c.
169b637a6b1SKautuk Consul */
170b637a6b1SKautuk Consul
171b637a6b1SKautuk Consul goto retry;
172b637a6b1SKautuk Consul }
1731da177e4SLinus Torvalds
174d8ed45c5SMichel Lespinasse mmap_read_unlock(mm);
1751da177e4SLinus Torvalds return 0;
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds /*
1781da177e4SLinus Torvalds * We ran out of memory, or some other thing happened to us that made
1791da177e4SLinus Torvalds * us unable to handle the page fault gracefully.
1801da177e4SLinus Torvalds */
1811da177e4SLinus Torvalds out_of_memory:
182d8ed45c5SMichel Lespinasse mmap_read_unlock(mm);
183adbf6e69SNick Piggin if (!user_mode(regs))
184adbf6e69SNick Piggin goto no_context;
185adbf6e69SNick Piggin pagefault_out_of_memory();
186adbf6e69SNick Piggin return 0;
1871da177e4SLinus Torvalds
1881da177e4SLinus Torvalds no_context:
1891da177e4SLinus Torvalds current->thread.signo = SIGBUS;
1901da177e4SLinus Torvalds current->thread.faddr = address;
1911da177e4SLinus Torvalds return send_fault_sig(regs);
1921da177e4SLinus Torvalds
1931da177e4SLinus Torvalds bus_err:
1941da177e4SLinus Torvalds current->thread.signo = SIGBUS;
1951da177e4SLinus Torvalds current->thread.code = BUS_ADRERR;
1961da177e4SLinus Torvalds current->thread.faddr = address;
1971da177e4SLinus Torvalds goto send_sig;
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvalds map_err:
200*8d7071afSLinus Torvalds mmap_read_unlock(mm);
201*8d7071afSLinus Torvalds map_err_nosemaphore:
2021da177e4SLinus Torvalds current->thread.signo = SIGSEGV;
2031da177e4SLinus Torvalds current->thread.code = SEGV_MAPERR;
2041da177e4SLinus Torvalds current->thread.faddr = address;
205*8d7071afSLinus Torvalds return send_fault_sig(regs);
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds acc_err:
2081da177e4SLinus Torvalds current->thread.signo = SIGSEGV;
2091da177e4SLinus Torvalds current->thread.code = SEGV_ACCERR;
2101da177e4SLinus Torvalds current->thread.faddr = address;
2111da177e4SLinus Torvalds
2121da177e4SLinus Torvalds send_sig:
213d8ed45c5SMichel Lespinasse mmap_read_unlock(mm);
2141da177e4SLinus Torvalds return send_fault_sig(regs);
2151da177e4SLinus Torvalds }
216