1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2c37ddd93SSam Ravnborg /* 3c37ddd93SSam Ravnborg * fault.c: Page fault handlers for the Sparc. 4c37ddd93SSam Ravnborg * 5c37ddd93SSam Ravnborg * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 6c37ddd93SSam Ravnborg * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) 7c37ddd93SSam Ravnborg * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 8c37ddd93SSam Ravnborg */ 9c37ddd93SSam Ravnborg 10c37ddd93SSam Ravnborg #include <asm/head.h> 11c37ddd93SSam Ravnborg 12c37ddd93SSam Ravnborg #include <linux/string.h> 13c37ddd93SSam Ravnborg #include <linux/types.h> 14c37ddd93SSam Ravnborg #include <linux/sched.h> 15c37ddd93SSam Ravnborg #include <linux/ptrace.h> 16c37ddd93SSam Ravnborg #include <linux/mman.h> 17c37ddd93SSam Ravnborg #include <linux/threads.h> 18c37ddd93SSam Ravnborg #include <linux/kernel.h> 19c37ddd93SSam Ravnborg #include <linux/signal.h> 20c37ddd93SSam Ravnborg #include <linux/mm.h> 21c37ddd93SSam Ravnborg #include <linux/smp.h> 22a084b667SDavid S. Miller #include <linux/perf_event.h> 23c37ddd93SSam Ravnborg #include <linux/interrupt.h> 24c37ddd93SSam Ravnborg #include <linux/kdebug.h> 2570ffdb93SDavid Hildenbrand #include <linux/uaccess.h> 26c37ddd93SSam Ravnborg 27c37ddd93SSam Ravnborg #include <asm/page.h> 28c37ddd93SSam Ravnborg #include <asm/pgtable.h> 29c37ddd93SSam Ravnborg #include <asm/openprom.h> 30c37ddd93SSam Ravnborg #include <asm/oplib.h> 319edfae3fSSam Ravnborg #include <asm/setup.h> 32c37ddd93SSam Ravnborg #include <asm/smp.h> 33c37ddd93SSam Ravnborg #include <asm/traps.h> 34c37ddd93SSam Ravnborg 35e1b2f134SSam Ravnborg #include "mm_32.h" 364b177647SDavid S. Miller 37e1b2f134SSam Ravnborg int show_unhandled_signals = 1; 38c37ddd93SSam Ravnborg 3970168dfaSSam Ravnborg static void __noreturn unhandled_fault(unsigned long address, 4070168dfaSSam Ravnborg struct task_struct *tsk, 41c37ddd93SSam Ravnborg struct pt_regs *regs) 42c37ddd93SSam Ravnborg { 43c37ddd93SSam Ravnborg if ((unsigned long) address < PAGE_SIZE) { 44c37ddd93SSam Ravnborg printk(KERN_ALERT 45c37ddd93SSam Ravnborg "Unable to handle kernel NULL pointer dereference\n"); 46c37ddd93SSam Ravnborg } else { 4770168dfaSSam Ravnborg printk(KERN_ALERT "Unable to handle kernel paging request at virtual address %08lx\n", 4870168dfaSSam Ravnborg address); 49c37ddd93SSam Ravnborg } 50c37ddd93SSam Ravnborg printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n", 51c37ddd93SSam Ravnborg (tsk->mm ? tsk->mm->context : tsk->active_mm->context)); 52c37ddd93SSam Ravnborg printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n", 53c37ddd93SSam Ravnborg (tsk->mm ? (unsigned long) tsk->mm->pgd : 54c37ddd93SSam Ravnborg (unsigned long) tsk->active_mm->pgd)); 55c37ddd93SSam Ravnborg die_if_kernel("Oops", regs); 56c37ddd93SSam Ravnborg } 57c37ddd93SSam Ravnborg 58c37ddd93SSam Ravnborg asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, 59c37ddd93SSam Ravnborg unsigned long address) 60c37ddd93SSam Ravnborg { 61c37ddd93SSam Ravnborg struct pt_regs regs; 62c37ddd93SSam Ravnborg unsigned long g2; 63c37ddd93SSam Ravnborg unsigned int insn; 64c37ddd93SSam Ravnborg int i; 65c37ddd93SSam Ravnborg 66c37ddd93SSam Ravnborg i = search_extables_range(ret_pc, &g2); 67c37ddd93SSam Ravnborg switch (i) { 68c37ddd93SSam Ravnborg case 3: 69c37ddd93SSam Ravnborg /* load & store will be handled by fixup */ 70c37ddd93SSam Ravnborg return 3; 71c37ddd93SSam Ravnborg 72c37ddd93SSam Ravnborg case 1: 73c37ddd93SSam Ravnborg /* store will be handled by fixup, load will bump out */ 74c37ddd93SSam Ravnborg /* for _to_ macros */ 75c37ddd93SSam Ravnborg insn = *((unsigned int *) pc); 76c37ddd93SSam Ravnborg if ((insn >> 21) & 1) 77c37ddd93SSam Ravnborg return 1; 78c37ddd93SSam Ravnborg break; 79c37ddd93SSam Ravnborg 80c37ddd93SSam Ravnborg case 2: 81c37ddd93SSam Ravnborg /* load will be handled by fixup, store will bump out */ 82c37ddd93SSam Ravnborg /* for _from_ macros */ 83c37ddd93SSam Ravnborg insn = *((unsigned int *) pc); 84c37ddd93SSam Ravnborg if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) 85c37ddd93SSam Ravnborg return 2; 86c37ddd93SSam Ravnborg break; 87c37ddd93SSam Ravnborg 88c37ddd93SSam Ravnborg default: 89c37ddd93SSam Ravnborg break; 906cb79b3fSJoe Perches } 91c37ddd93SSam Ravnborg 92c37ddd93SSam Ravnborg memset(®s, 0, sizeof(regs)); 93c37ddd93SSam Ravnborg regs.pc = pc; 94c37ddd93SSam Ravnborg regs.npc = pc + 4; 95c37ddd93SSam Ravnborg __asm__ __volatile__( 96c37ddd93SSam Ravnborg "rd %%psr, %0\n\t" 97c37ddd93SSam Ravnborg "nop\n\t" 98c37ddd93SSam Ravnborg "nop\n\t" 99c37ddd93SSam Ravnborg "nop\n" : "=r" (regs.psr)); 100c37ddd93SSam Ravnborg unhandled_fault(address, current, ®s); 101c37ddd93SSam Ravnborg 102c37ddd93SSam Ravnborg /* Not reached */ 103c37ddd93SSam Ravnborg return 0; 104c37ddd93SSam Ravnborg } 105c37ddd93SSam Ravnborg 1064b177647SDavid S. Miller static inline void 1074b177647SDavid S. Miller show_signal_msg(struct pt_regs *regs, int sig, int code, 1084b177647SDavid S. Miller unsigned long address, struct task_struct *tsk) 1094b177647SDavid S. Miller { 1104b177647SDavid S. Miller if (!unhandled_signal(tsk, sig)) 1114b177647SDavid S. Miller return; 1124b177647SDavid S. Miller 1134b177647SDavid S. Miller if (!printk_ratelimit()) 1144b177647SDavid S. Miller return; 1154b177647SDavid S. Miller 11610a7e9d8SKees Cook printk("%s%s[%d]: segfault at %lx ip %px (rpc %px) sp %px error %x", 1174b177647SDavid S. Miller task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, 1184b177647SDavid S. Miller tsk->comm, task_pid_nr(tsk), address, 1194b177647SDavid S. Miller (void *)regs->pc, (void *)regs->u_regs[UREG_I7], 1204b177647SDavid S. Miller (void *)regs->u_regs[UREG_FP], code); 1214b177647SDavid S. Miller 1224b177647SDavid S. Miller print_vma_addr(KERN_CONT " in ", regs->pc); 1234b177647SDavid S. Miller 1244b177647SDavid S. Miller printk(KERN_CONT "\n"); 1254b177647SDavid S. Miller } 1264b177647SDavid S. Miller 1274b177647SDavid S. Miller static void __do_fault_siginfo(int code, int sig, struct pt_regs *regs, 1284b177647SDavid S. Miller unsigned long addr) 1294b177647SDavid S. Miller { 1304b177647SDavid S. Miller if (unlikely(show_unhandled_signals)) 131d1f5bef6SEric W. Biederman show_signal_msg(regs, sig, code, 1324b177647SDavid S. Miller addr, current); 1334b177647SDavid S. Miller 1342e1661d2SEric W. Biederman force_sig_fault(sig, code, (void __user *) addr, 0); 1354b177647SDavid S. Miller } 1364b177647SDavid S. Miller 137c37ddd93SSam Ravnborg static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault) 138c37ddd93SSam Ravnborg { 139c37ddd93SSam Ravnborg unsigned int insn; 140c37ddd93SSam Ravnborg 141c37ddd93SSam Ravnborg if (text_fault) 142c37ddd93SSam Ravnborg return regs->pc; 143c37ddd93SSam Ravnborg 14470168dfaSSam Ravnborg if (regs->psr & PSR_PS) 145c37ddd93SSam Ravnborg insn = *(unsigned int *) regs->pc; 14670168dfaSSam Ravnborg else 147c37ddd93SSam Ravnborg __get_user(insn, (unsigned int *) regs->pc); 148c37ddd93SSam Ravnborg 149c37ddd93SSam Ravnborg return safe_compute_effective_address(regs, insn); 150c37ddd93SSam Ravnborg } 151c37ddd93SSam Ravnborg 1524b177647SDavid S. Miller static noinline void do_fault_siginfo(int code, int sig, struct pt_regs *regs, 1534b177647SDavid S. Miller int text_fault) 1544b177647SDavid S. Miller { 1554b177647SDavid S. Miller unsigned long addr = compute_si_addr(regs, text_fault); 1564b177647SDavid S. Miller 1574b177647SDavid S. Miller __do_fault_siginfo(code, sig, regs, addr); 1584b177647SDavid S. Miller } 1594b177647SDavid S. Miller 160c37ddd93SSam Ravnborg asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, 161c37ddd93SSam Ravnborg unsigned long address) 162c37ddd93SSam Ravnborg { 163c37ddd93SSam Ravnborg struct vm_area_struct *vma; 164c37ddd93SSam Ravnborg struct task_struct *tsk = current; 165c37ddd93SSam Ravnborg struct mm_struct *mm = tsk->mm; 166c37ddd93SSam Ravnborg unsigned int fixup; 167c37ddd93SSam Ravnborg unsigned long g2; 168c37ddd93SSam Ravnborg int from_user = !(regs->psr & PSR_PS); 16950a7ca3cSSouptick Joarder int code; 17050a7ca3cSSouptick Joarder vm_fault_t fault; 171759496baSJohannes Weiner unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; 172c37ddd93SSam Ravnborg 173c37ddd93SSam Ravnborg if (text_fault) 174c37ddd93SSam Ravnborg address = regs->pc; 175c37ddd93SSam Ravnborg 176c37ddd93SSam Ravnborg /* 177c37ddd93SSam Ravnborg * We fault-in kernel-space virtual memory on-demand. The 178c37ddd93SSam Ravnborg * 'reference' page table is init_mm.pgd. 179c37ddd93SSam Ravnborg * 180c37ddd93SSam Ravnborg * NOTE! We MUST NOT take any locks for this case. We may 181c37ddd93SSam Ravnborg * be in an interrupt or a critical region, and should 182c37ddd93SSam Ravnborg * only copy the information from the master page table, 183c37ddd93SSam Ravnborg * nothing more. 184c37ddd93SSam Ravnborg */ 185c816be7bSDavid S. Miller code = SEGV_MAPERR; 186582a0baeSSam Ravnborg if (address >= TASK_SIZE) 187c37ddd93SSam Ravnborg goto vmalloc_fault; 188c37ddd93SSam Ravnborg 189c37ddd93SSam Ravnborg /* 190c37ddd93SSam Ravnborg * If we're in an interrupt or have no user 191c37ddd93SSam Ravnborg * context, we must not take the fault.. 192c37ddd93SSam Ravnborg */ 19370ffdb93SDavid Hildenbrand if (pagefault_disabled() || !mm) 194c37ddd93SSam Ravnborg goto no_context; 195c37ddd93SSam Ravnborg 196a8b0ca17SPeter Zijlstra perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); 197a084b667SDavid S. Miller 198c29554f5SKautuk Consul retry: 199c37ddd93SSam Ravnborg down_read(&mm->mmap_sem); 200c37ddd93SSam Ravnborg 201c37ddd93SSam Ravnborg if (!from_user && address >= PAGE_OFFSET) 202c37ddd93SSam Ravnborg goto bad_area; 203c37ddd93SSam Ravnborg 204c37ddd93SSam Ravnborg vma = find_vma(mm, address); 205c37ddd93SSam Ravnborg if (!vma) 206c37ddd93SSam Ravnborg goto bad_area; 207c37ddd93SSam Ravnborg if (vma->vm_start <= address) 208c37ddd93SSam Ravnborg goto good_area; 209c37ddd93SSam Ravnborg if (!(vma->vm_flags & VM_GROWSDOWN)) 210c37ddd93SSam Ravnborg goto bad_area; 211c37ddd93SSam Ravnborg if (expand_stack(vma, address)) 212c37ddd93SSam Ravnborg goto bad_area; 213c37ddd93SSam Ravnborg /* 214c37ddd93SSam Ravnborg * Ok, we have a good vm_area for this memory access, so 215c37ddd93SSam Ravnborg * we can handle it.. 216c37ddd93SSam Ravnborg */ 217c37ddd93SSam Ravnborg good_area: 2184b177647SDavid S. Miller code = SEGV_ACCERR; 219c37ddd93SSam Ravnborg if (write) { 220c37ddd93SSam Ravnborg if (!(vma->vm_flags & VM_WRITE)) 221c37ddd93SSam Ravnborg goto bad_area; 222c37ddd93SSam Ravnborg } else { 223c37ddd93SSam Ravnborg /* Allow reads even for write-only mappings */ 224c37ddd93SSam Ravnborg if (!(vma->vm_flags & (VM_READ | VM_EXEC))) 225c37ddd93SSam Ravnborg goto bad_area; 226c37ddd93SSam Ravnborg } 227c37ddd93SSam Ravnborg 228759496baSJohannes Weiner if (from_user) 229759496baSJohannes Weiner flags |= FAULT_FLAG_USER; 230759496baSJohannes Weiner if (write) 231759496baSJohannes Weiner flags |= FAULT_FLAG_WRITE; 232759496baSJohannes Weiner 233c37ddd93SSam Ravnborg /* 234c37ddd93SSam Ravnborg * If for any reason at all we couldn't handle the fault, 235c37ddd93SSam Ravnborg * make sure we exit gracefully rather than endlessly redo 236c37ddd93SSam Ravnborg * the fault. 237c37ddd93SSam Ravnborg */ 238dcddffd4SKirill A. Shutemov fault = handle_mm_fault(vma, address, flags); 239c29554f5SKautuk Consul 240c29554f5SKautuk Consul if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) 241c29554f5SKautuk Consul return; 242c29554f5SKautuk Consul 243c37ddd93SSam Ravnborg if (unlikely(fault & VM_FAULT_ERROR)) { 244c37ddd93SSam Ravnborg if (fault & VM_FAULT_OOM) 245c37ddd93SSam Ravnborg goto out_of_memory; 24633692f27SLinus Torvalds else if (fault & VM_FAULT_SIGSEGV) 24733692f27SLinus Torvalds goto bad_area; 248c37ddd93SSam Ravnborg else if (fault & VM_FAULT_SIGBUS) 249c37ddd93SSam Ravnborg goto do_sigbus; 250c37ddd93SSam Ravnborg BUG(); 251c37ddd93SSam Ravnborg } 252c29554f5SKautuk Consul 253c29554f5SKautuk Consul if (flags & FAULT_FLAG_ALLOW_RETRY) { 254a084b667SDavid S. Miller if (fault & VM_FAULT_MAJOR) { 255c37ddd93SSam Ravnborg current->maj_flt++; 256c29554f5SKautuk Consul perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 257c29554f5SKautuk Consul 1, regs, address); 258a084b667SDavid S. Miller } else { 259c37ddd93SSam Ravnborg current->min_flt++; 260c29554f5SKautuk Consul perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 261c29554f5SKautuk Consul 1, regs, address); 262a084b667SDavid S. Miller } 263c29554f5SKautuk Consul if (fault & VM_FAULT_RETRY) { 264c29554f5SKautuk Consul flags &= ~FAULT_FLAG_ALLOW_RETRY; 26545cac65bSShaohua Li flags |= FAULT_FLAG_TRIED; 266c29554f5SKautuk Consul 267c29554f5SKautuk Consul /* No need to up_read(&mm->mmap_sem) as we would 268c29554f5SKautuk Consul * have already released it in __lock_page_or_retry 269c29554f5SKautuk Consul * in mm/filemap.c. 270c29554f5SKautuk Consul */ 271c29554f5SKautuk Consul 272c29554f5SKautuk Consul goto retry; 273c29554f5SKautuk Consul } 274c29554f5SKautuk Consul } 275c29554f5SKautuk Consul 276c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 277c37ddd93SSam Ravnborg return; 278c37ddd93SSam Ravnborg 279c37ddd93SSam Ravnborg /* 280c37ddd93SSam Ravnborg * Something tried to access memory that isn't in our memory map.. 281c37ddd93SSam Ravnborg * Fix it, but check if it's kernel or user first.. 282c37ddd93SSam Ravnborg */ 283c37ddd93SSam Ravnborg bad_area: 284c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 285c37ddd93SSam Ravnborg 286c37ddd93SSam Ravnborg bad_area_nosemaphore: 287c37ddd93SSam Ravnborg /* User mode accesses just cause a SIGSEGV */ 288c37ddd93SSam Ravnborg if (from_user) { 2894b177647SDavid S. Miller do_fault_siginfo(code, SIGSEGV, regs, text_fault); 290c37ddd93SSam Ravnborg return; 291c37ddd93SSam Ravnborg } 292c37ddd93SSam Ravnborg 293c37ddd93SSam Ravnborg /* Is this in ex_table? */ 294c37ddd93SSam Ravnborg no_context: 295c37ddd93SSam Ravnborg g2 = regs->u_regs[UREG_G2]; 2960157141aSSam Ravnborg if (!from_user) { 2970157141aSSam Ravnborg fixup = search_extables_range(regs->pc, &g2); 29870168dfaSSam Ravnborg /* Values below 10 are reserved for other things */ 29970168dfaSSam Ravnborg if (fixup > 10) { 3009ef595d8SJoe Perches extern const unsigned int __memset_start[]; 3019ef595d8SJoe Perches extern const unsigned int __memset_end[]; 3029ef595d8SJoe Perches extern const unsigned int __csum_partial_copy_start[]; 3039ef595d8SJoe Perches extern const unsigned int __csum_partial_copy_end[]; 304c37ddd93SSam Ravnborg 305c37ddd93SSam Ravnborg #ifdef DEBUG_EXCEPTIONS 30670168dfaSSam Ravnborg printk("Exception: PC<%08lx> faddr<%08lx>\n", 30770168dfaSSam Ravnborg regs->pc, address); 308c37ddd93SSam Ravnborg printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n", 309c37ddd93SSam Ravnborg regs->pc, fixup, g2); 310c37ddd93SSam Ravnborg #endif 311c37ddd93SSam Ravnborg if ((regs->pc >= (unsigned long)__memset_start && 312c37ddd93SSam Ravnborg regs->pc < (unsigned long)__memset_end) || 313c37ddd93SSam Ravnborg (regs->pc >= (unsigned long)__csum_partial_copy_start && 314c37ddd93SSam Ravnborg regs->pc < (unsigned long)__csum_partial_copy_end)) { 315c37ddd93SSam Ravnborg regs->u_regs[UREG_I4] = address; 316c37ddd93SSam Ravnborg regs->u_regs[UREG_I5] = regs->pc; 317c37ddd93SSam Ravnborg } 318c37ddd93SSam Ravnborg regs->u_regs[UREG_G2] = g2; 319c37ddd93SSam Ravnborg regs->pc = fixup; 320c37ddd93SSam Ravnborg regs->npc = regs->pc + 4; 321c37ddd93SSam Ravnborg return; 322c37ddd93SSam Ravnborg } 323c37ddd93SSam Ravnborg } 324c37ddd93SSam Ravnborg 325c37ddd93SSam Ravnborg unhandled_fault(address, tsk, regs); 326c37ddd93SSam Ravnborg do_exit(SIGKILL); 327c37ddd93SSam Ravnborg 328c37ddd93SSam Ravnborg /* 329c37ddd93SSam Ravnborg * We ran out of memory, or some other thing happened to us that made 330c37ddd93SSam Ravnborg * us unable to handle the page fault gracefully. 331c37ddd93SSam Ravnborg */ 332c37ddd93SSam Ravnborg out_of_memory: 333c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 334a923c28fSDavid S. Miller if (from_user) { 335a923c28fSDavid S. Miller pagefault_out_of_memory(); 336a923c28fSDavid S. Miller return; 337a923c28fSDavid S. Miller } 338c37ddd93SSam Ravnborg goto no_context; 339c37ddd93SSam Ravnborg 340c37ddd93SSam Ravnborg do_sigbus: 341c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 3424b177647SDavid S. Miller do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, text_fault); 343c37ddd93SSam Ravnborg if (!from_user) 344c37ddd93SSam Ravnborg goto no_context; 345c37ddd93SSam Ravnborg 346c37ddd93SSam Ravnborg vmalloc_fault: 347c37ddd93SSam Ravnborg { 348c37ddd93SSam Ravnborg /* 349c37ddd93SSam Ravnborg * Synchronize this task's top level page-table 350c37ddd93SSam Ravnborg * with the 'reference' page table. 351c37ddd93SSam Ravnborg */ 352c37ddd93SSam Ravnborg int offset = pgd_index(address); 353c37ddd93SSam Ravnborg pgd_t *pgd, *pgd_k; 3547235db26SMike Rapoport p4d_t *p4d, *p4d_k; 3557235db26SMike Rapoport pud_t *pud, *pud_k; 356c37ddd93SSam Ravnborg pmd_t *pmd, *pmd_k; 357c37ddd93SSam Ravnborg 358c37ddd93SSam Ravnborg pgd = tsk->active_mm->pgd + offset; 359c37ddd93SSam Ravnborg pgd_k = init_mm.pgd + offset; 360c37ddd93SSam Ravnborg 361c37ddd93SSam Ravnborg if (!pgd_present(*pgd)) { 362c37ddd93SSam Ravnborg if (!pgd_present(*pgd_k)) 363c37ddd93SSam Ravnborg goto bad_area_nosemaphore; 364c37ddd93SSam Ravnborg pgd_val(*pgd) = pgd_val(*pgd_k); 365c37ddd93SSam Ravnborg return; 366c37ddd93SSam Ravnborg } 367c37ddd93SSam Ravnborg 3687235db26SMike Rapoport p4d = p4d_offset(pgd, address); 3697235db26SMike Rapoport pud = pud_offset(p4d, address); 3707235db26SMike Rapoport pmd = pmd_offset(pud, address); 3717235db26SMike Rapoport 3727235db26SMike Rapoport p4d_k = p4d_offset(pgd_k, address); 3737235db26SMike Rapoport pud_k = pud_offset(p4d_k, address); 3747235db26SMike Rapoport pmd_k = pmd_offset(pud_k, address); 375c37ddd93SSam Ravnborg 376c37ddd93SSam Ravnborg if (pmd_present(*pmd) || !pmd_present(*pmd_k)) 377c37ddd93SSam Ravnborg goto bad_area_nosemaphore; 37870168dfaSSam Ravnborg 379c37ddd93SSam Ravnborg *pmd = *pmd_k; 380c37ddd93SSam Ravnborg return; 381c37ddd93SSam Ravnborg } 382c37ddd93SSam Ravnborg } 383c37ddd93SSam Ravnborg 384c37ddd93SSam Ravnborg /* This always deals with user addresses. */ 385c37ddd93SSam Ravnborg static void force_user_fault(unsigned long address, int write) 386c37ddd93SSam Ravnborg { 387c37ddd93SSam Ravnborg struct vm_area_struct *vma; 388c37ddd93SSam Ravnborg struct task_struct *tsk = current; 389c37ddd93SSam Ravnborg struct mm_struct *mm = tsk->mm; 390759496baSJohannes Weiner unsigned int flags = FAULT_FLAG_USER; 3914b177647SDavid S. Miller int code; 392c37ddd93SSam Ravnborg 3934b177647SDavid S. Miller code = SEGV_MAPERR; 394c37ddd93SSam Ravnborg 395c37ddd93SSam Ravnborg down_read(&mm->mmap_sem); 396c37ddd93SSam Ravnborg vma = find_vma(mm, address); 397c37ddd93SSam Ravnborg if (!vma) 398c37ddd93SSam Ravnborg goto bad_area; 399c37ddd93SSam Ravnborg if (vma->vm_start <= address) 400c37ddd93SSam Ravnborg goto good_area; 401c37ddd93SSam Ravnborg if (!(vma->vm_flags & VM_GROWSDOWN)) 402c37ddd93SSam Ravnborg goto bad_area; 403c37ddd93SSam Ravnborg if (expand_stack(vma, address)) 404c37ddd93SSam Ravnborg goto bad_area; 405c37ddd93SSam Ravnborg good_area: 4064b177647SDavid S. Miller code = SEGV_ACCERR; 407c37ddd93SSam Ravnborg if (write) { 408c37ddd93SSam Ravnborg if (!(vma->vm_flags & VM_WRITE)) 409c37ddd93SSam Ravnborg goto bad_area; 410759496baSJohannes Weiner flags |= FAULT_FLAG_WRITE; 411c37ddd93SSam Ravnborg } else { 412c37ddd93SSam Ravnborg if (!(vma->vm_flags & (VM_READ | VM_EXEC))) 413c37ddd93SSam Ravnborg goto bad_area; 414c37ddd93SSam Ravnborg } 415dcddffd4SKirill A. Shutemov switch (handle_mm_fault(vma, address, flags)) { 416c37ddd93SSam Ravnborg case VM_FAULT_SIGBUS: 417c37ddd93SSam Ravnborg case VM_FAULT_OOM: 418c37ddd93SSam Ravnborg goto do_sigbus; 419c37ddd93SSam Ravnborg } 420c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 421c37ddd93SSam Ravnborg return; 422c37ddd93SSam Ravnborg bad_area: 423c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 4244b177647SDavid S. Miller __do_fault_siginfo(code, SIGSEGV, tsk->thread.kregs, address); 425c37ddd93SSam Ravnborg return; 426c37ddd93SSam Ravnborg 427c37ddd93SSam Ravnborg do_sigbus: 428c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 4294b177647SDavid S. Miller __do_fault_siginfo(BUS_ADRERR, SIGBUS, tsk->thread.kregs, address); 430c37ddd93SSam Ravnborg } 431c37ddd93SSam Ravnborg 4329088333eSDavid S. Miller static void check_stack_aligned(unsigned long sp) 4339088333eSDavid S. Miller { 4349088333eSDavid S. Miller if (sp & 0x7UL) 4353cf5d076SEric W. Biederman force_sig(SIGILL); 4369088333eSDavid S. Miller } 4379088333eSDavid S. Miller 438c37ddd93SSam Ravnborg void window_overflow_fault(void) 439c37ddd93SSam Ravnborg { 440c37ddd93SSam Ravnborg unsigned long sp; 441c37ddd93SSam Ravnborg 442c37ddd93SSam Ravnborg sp = current_thread_info()->rwbuf_stkptrs[0]; 443c37ddd93SSam Ravnborg if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) 444c37ddd93SSam Ravnborg force_user_fault(sp + 0x38, 1); 445c37ddd93SSam Ravnborg force_user_fault(sp, 1); 4469088333eSDavid S. Miller 4479088333eSDavid S. Miller check_stack_aligned(sp); 448c37ddd93SSam Ravnborg } 449c37ddd93SSam Ravnborg 450c37ddd93SSam Ravnborg void window_underflow_fault(unsigned long sp) 451c37ddd93SSam Ravnborg { 452c37ddd93SSam Ravnborg if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) 453c37ddd93SSam Ravnborg force_user_fault(sp + 0x38, 0); 454c37ddd93SSam Ravnborg force_user_fault(sp, 0); 4559088333eSDavid S. Miller 4569088333eSDavid S. Miller check_stack_aligned(sp); 457c37ddd93SSam Ravnborg } 458c37ddd93SSam Ravnborg 459c37ddd93SSam Ravnborg void window_ret_fault(struct pt_regs *regs) 460c37ddd93SSam Ravnborg { 461c37ddd93SSam Ravnborg unsigned long sp; 462c37ddd93SSam Ravnborg 463c37ddd93SSam Ravnborg sp = regs->u_regs[UREG_FP]; 464c37ddd93SSam Ravnborg if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) 465c37ddd93SSam Ravnborg force_user_fault(sp + 0x38, 0); 466c37ddd93SSam Ravnborg force_user_fault(sp, 0); 4679088333eSDavid S. Miller 4689088333eSDavid S. Miller check_stack_aligned(sp); 469c37ddd93SSam Ravnborg } 470