1c37ddd93SSam Ravnborg /* 2c37ddd93SSam Ravnborg * fault.c: Page fault handlers for the Sparc. 3c37ddd93SSam Ravnborg * 4c37ddd93SSam Ravnborg * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 5c37ddd93SSam Ravnborg * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) 6c37ddd93SSam Ravnborg * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 7c37ddd93SSam Ravnborg */ 8c37ddd93SSam Ravnborg 9c37ddd93SSam Ravnborg #include <asm/head.h> 10c37ddd93SSam Ravnborg 11c37ddd93SSam Ravnborg #include <linux/string.h> 12c37ddd93SSam Ravnborg #include <linux/types.h> 13c37ddd93SSam Ravnborg #include <linux/sched.h> 14c37ddd93SSam Ravnborg #include <linux/ptrace.h> 15c37ddd93SSam Ravnborg #include <linux/mman.h> 16c37ddd93SSam Ravnborg #include <linux/threads.h> 17c37ddd93SSam Ravnborg #include <linux/kernel.h> 18c37ddd93SSam Ravnborg #include <linux/signal.h> 19c37ddd93SSam Ravnborg #include <linux/mm.h> 20c37ddd93SSam Ravnborg #include <linux/smp.h> 21a084b667SDavid S. Miller #include <linux/perf_event.h> 22c37ddd93SSam Ravnborg #include <linux/interrupt.h> 23c37ddd93SSam Ravnborg #include <linux/kdebug.h> 2470ffdb93SDavid Hildenbrand #include <linux/uaccess.h> 25c37ddd93SSam Ravnborg 26c37ddd93SSam Ravnborg #include <asm/page.h> 27c37ddd93SSam Ravnborg #include <asm/pgtable.h> 28c37ddd93SSam Ravnborg #include <asm/openprom.h> 29c37ddd93SSam Ravnborg #include <asm/oplib.h> 309edfae3fSSam Ravnborg #include <asm/setup.h> 31c37ddd93SSam Ravnborg #include <asm/smp.h> 32c37ddd93SSam Ravnborg #include <asm/traps.h> 33c37ddd93SSam Ravnborg 34e1b2f134SSam Ravnborg #include "mm_32.h" 354b177647SDavid S. Miller 36e1b2f134SSam Ravnborg int show_unhandled_signals = 1; 37c37ddd93SSam Ravnborg 3870168dfaSSam Ravnborg static void __noreturn unhandled_fault(unsigned long address, 3970168dfaSSam Ravnborg struct task_struct *tsk, 40c37ddd93SSam Ravnborg struct pt_regs *regs) 41c37ddd93SSam Ravnborg { 42c37ddd93SSam Ravnborg if ((unsigned long) address < PAGE_SIZE) { 43c37ddd93SSam Ravnborg printk(KERN_ALERT 44c37ddd93SSam Ravnborg "Unable to handle kernel NULL pointer dereference\n"); 45c37ddd93SSam Ravnborg } else { 4670168dfaSSam Ravnborg printk(KERN_ALERT "Unable to handle kernel paging request at virtual address %08lx\n", 4770168dfaSSam Ravnborg address); 48c37ddd93SSam Ravnborg } 49c37ddd93SSam Ravnborg printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n", 50c37ddd93SSam Ravnborg (tsk->mm ? tsk->mm->context : tsk->active_mm->context)); 51c37ddd93SSam Ravnborg printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n", 52c37ddd93SSam Ravnborg (tsk->mm ? (unsigned long) tsk->mm->pgd : 53c37ddd93SSam Ravnborg (unsigned long) tsk->active_mm->pgd)); 54c37ddd93SSam Ravnborg die_if_kernel("Oops", regs); 55c37ddd93SSam Ravnborg } 56c37ddd93SSam Ravnborg 57c37ddd93SSam Ravnborg asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, 58c37ddd93SSam Ravnborg unsigned long address) 59c37ddd93SSam Ravnborg { 60c37ddd93SSam Ravnborg struct pt_regs regs; 61c37ddd93SSam Ravnborg unsigned long g2; 62c37ddd93SSam Ravnborg unsigned int insn; 63c37ddd93SSam Ravnborg int i; 64c37ddd93SSam Ravnborg 65c37ddd93SSam Ravnborg i = search_extables_range(ret_pc, &g2); 66c37ddd93SSam Ravnborg switch (i) { 67c37ddd93SSam Ravnborg case 3: 68c37ddd93SSam Ravnborg /* load & store will be handled by fixup */ 69c37ddd93SSam Ravnborg return 3; 70c37ddd93SSam Ravnborg 71c37ddd93SSam Ravnborg case 1: 72c37ddd93SSam Ravnborg /* store will be handled by fixup, load will bump out */ 73c37ddd93SSam Ravnborg /* for _to_ macros */ 74c37ddd93SSam Ravnborg insn = *((unsigned int *) pc); 75c37ddd93SSam Ravnborg if ((insn >> 21) & 1) 76c37ddd93SSam Ravnborg return 1; 77c37ddd93SSam Ravnborg break; 78c37ddd93SSam Ravnborg 79c37ddd93SSam Ravnborg case 2: 80c37ddd93SSam Ravnborg /* load will be handled by fixup, store will bump out */ 81c37ddd93SSam Ravnborg /* for _from_ macros */ 82c37ddd93SSam Ravnborg insn = *((unsigned int *) pc); 83c37ddd93SSam Ravnborg if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) 84c37ddd93SSam Ravnborg return 2; 85c37ddd93SSam Ravnborg break; 86c37ddd93SSam Ravnborg 87c37ddd93SSam Ravnborg default: 88c37ddd93SSam Ravnborg break; 896cb79b3fSJoe Perches } 90c37ddd93SSam Ravnborg 91c37ddd93SSam Ravnborg memset(®s, 0, sizeof(regs)); 92c37ddd93SSam Ravnborg regs.pc = pc; 93c37ddd93SSam Ravnborg regs.npc = pc + 4; 94c37ddd93SSam Ravnborg __asm__ __volatile__( 95c37ddd93SSam Ravnborg "rd %%psr, %0\n\t" 96c37ddd93SSam Ravnborg "nop\n\t" 97c37ddd93SSam Ravnborg "nop\n\t" 98c37ddd93SSam Ravnborg "nop\n" : "=r" (regs.psr)); 99c37ddd93SSam Ravnborg unhandled_fault(address, current, ®s); 100c37ddd93SSam Ravnborg 101c37ddd93SSam Ravnborg /* Not reached */ 102c37ddd93SSam Ravnborg return 0; 103c37ddd93SSam Ravnborg } 104c37ddd93SSam Ravnborg 1054b177647SDavid S. Miller static inline void 1064b177647SDavid S. Miller show_signal_msg(struct pt_regs *regs, int sig, int code, 1074b177647SDavid S. Miller unsigned long address, struct task_struct *tsk) 1084b177647SDavid S. Miller { 1094b177647SDavid S. Miller if (!unhandled_signal(tsk, sig)) 1104b177647SDavid S. Miller return; 1114b177647SDavid S. Miller 1124b177647SDavid S. Miller if (!printk_ratelimit()) 1134b177647SDavid S. Miller return; 1144b177647SDavid S. Miller 1154b177647SDavid S. Miller printk("%s%s[%d]: segfault at %lx ip %p (rpc %p) sp %p error %x", 1164b177647SDavid S. Miller task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, 1174b177647SDavid S. Miller tsk->comm, task_pid_nr(tsk), address, 1184b177647SDavid S. Miller (void *)regs->pc, (void *)regs->u_regs[UREG_I7], 1194b177647SDavid S. Miller (void *)regs->u_regs[UREG_FP], code); 1204b177647SDavid S. Miller 1214b177647SDavid S. Miller print_vma_addr(KERN_CONT " in ", regs->pc); 1224b177647SDavid S. Miller 1234b177647SDavid S. Miller printk(KERN_CONT "\n"); 1244b177647SDavid S. Miller } 1254b177647SDavid S. Miller 1264b177647SDavid S. Miller static void __do_fault_siginfo(int code, int sig, struct pt_regs *regs, 1274b177647SDavid S. Miller unsigned long addr) 1284b177647SDavid S. Miller { 1294b177647SDavid S. Miller siginfo_t info; 1304b177647SDavid S. Miller 1314b177647SDavid S. Miller info.si_signo = sig; 1324b177647SDavid S. Miller info.si_code = code; 1334b177647SDavid S. Miller info.si_errno = 0; 1344b177647SDavid S. Miller info.si_addr = (void __user *) addr; 1354b177647SDavid S. Miller info.si_trapno = 0; 1364b177647SDavid S. Miller 1374b177647SDavid S. Miller if (unlikely(show_unhandled_signals)) 1384b177647SDavid S. Miller show_signal_msg(regs, sig, info.si_code, 1394b177647SDavid S. Miller addr, current); 1404b177647SDavid S. Miller 1414b177647SDavid S. Miller force_sig_info (sig, &info, current); 1424b177647SDavid S. Miller } 1434b177647SDavid S. Miller 144c37ddd93SSam Ravnborg static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault) 145c37ddd93SSam Ravnborg { 146c37ddd93SSam Ravnborg unsigned int insn; 147c37ddd93SSam Ravnborg 148c37ddd93SSam Ravnborg if (text_fault) 149c37ddd93SSam Ravnborg return regs->pc; 150c37ddd93SSam Ravnborg 15170168dfaSSam Ravnborg if (regs->psr & PSR_PS) 152c37ddd93SSam Ravnborg insn = *(unsigned int *) regs->pc; 15370168dfaSSam Ravnborg else 154c37ddd93SSam Ravnborg __get_user(insn, (unsigned int *) regs->pc); 155c37ddd93SSam Ravnborg 156c37ddd93SSam Ravnborg return safe_compute_effective_address(regs, insn); 157c37ddd93SSam Ravnborg } 158c37ddd93SSam Ravnborg 1594b177647SDavid S. Miller static noinline void do_fault_siginfo(int code, int sig, struct pt_regs *regs, 1604b177647SDavid S. Miller int text_fault) 1614b177647SDavid S. Miller { 1624b177647SDavid S. Miller unsigned long addr = compute_si_addr(regs, text_fault); 1634b177647SDavid S. Miller 1644b177647SDavid S. Miller __do_fault_siginfo(code, sig, regs, addr); 1654b177647SDavid S. Miller } 1664b177647SDavid S. Miller 167c37ddd93SSam Ravnborg asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, 168c37ddd93SSam Ravnborg unsigned long address) 169c37ddd93SSam Ravnborg { 170c37ddd93SSam Ravnborg struct vm_area_struct *vma; 171c37ddd93SSam Ravnborg struct task_struct *tsk = current; 172c37ddd93SSam Ravnborg struct mm_struct *mm = tsk->mm; 173c37ddd93SSam Ravnborg unsigned int fixup; 174c37ddd93SSam Ravnborg unsigned long g2; 175c37ddd93SSam Ravnborg int from_user = !(regs->psr & PSR_PS); 1764b177647SDavid S. Miller int fault, code; 177759496baSJohannes Weiner unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; 178c37ddd93SSam Ravnborg 179c37ddd93SSam Ravnborg if (text_fault) 180c37ddd93SSam Ravnborg address = regs->pc; 181c37ddd93SSam Ravnborg 182c37ddd93SSam Ravnborg /* 183c37ddd93SSam Ravnborg * We fault-in kernel-space virtual memory on-demand. The 184c37ddd93SSam Ravnborg * 'reference' page table is init_mm.pgd. 185c37ddd93SSam Ravnborg * 186c37ddd93SSam Ravnborg * NOTE! We MUST NOT take any locks for this case. We may 187c37ddd93SSam Ravnborg * be in an interrupt or a critical region, and should 188c37ddd93SSam Ravnborg * only copy the information from the master page table, 189c37ddd93SSam Ravnborg * nothing more. 190c37ddd93SSam Ravnborg */ 191c816be7bSDavid S. Miller code = SEGV_MAPERR; 192582a0baeSSam Ravnborg if (address >= TASK_SIZE) 193c37ddd93SSam Ravnborg goto vmalloc_fault; 194c37ddd93SSam Ravnborg 195c37ddd93SSam Ravnborg /* 196c37ddd93SSam Ravnborg * If we're in an interrupt or have no user 197c37ddd93SSam Ravnborg * context, we must not take the fault.. 198c37ddd93SSam Ravnborg */ 19970ffdb93SDavid Hildenbrand if (pagefault_disabled() || !mm) 200c37ddd93SSam Ravnborg goto no_context; 201c37ddd93SSam Ravnborg 202a8b0ca17SPeter Zijlstra perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); 203a084b667SDavid S. Miller 204c29554f5SKautuk Consul retry: 205c37ddd93SSam Ravnborg down_read(&mm->mmap_sem); 206c37ddd93SSam Ravnborg 207c37ddd93SSam Ravnborg if (!from_user && address >= PAGE_OFFSET) 208c37ddd93SSam Ravnborg goto bad_area; 209c37ddd93SSam Ravnborg 210c37ddd93SSam Ravnborg vma = find_vma(mm, address); 211c37ddd93SSam Ravnborg if (!vma) 212c37ddd93SSam Ravnborg goto bad_area; 213c37ddd93SSam Ravnborg if (vma->vm_start <= address) 214c37ddd93SSam Ravnborg goto good_area; 215c37ddd93SSam Ravnborg if (!(vma->vm_flags & VM_GROWSDOWN)) 216c37ddd93SSam Ravnborg goto bad_area; 217c37ddd93SSam Ravnborg if (expand_stack(vma, address)) 218c37ddd93SSam Ravnborg goto bad_area; 219c37ddd93SSam Ravnborg /* 220c37ddd93SSam Ravnborg * Ok, we have a good vm_area for this memory access, so 221c37ddd93SSam Ravnborg * we can handle it.. 222c37ddd93SSam Ravnborg */ 223c37ddd93SSam Ravnborg good_area: 2244b177647SDavid S. Miller code = SEGV_ACCERR; 225c37ddd93SSam Ravnborg if (write) { 226c37ddd93SSam Ravnborg if (!(vma->vm_flags & VM_WRITE)) 227c37ddd93SSam Ravnborg goto bad_area; 228c37ddd93SSam Ravnborg } else { 229c37ddd93SSam Ravnborg /* Allow reads even for write-only mappings */ 230c37ddd93SSam Ravnborg if (!(vma->vm_flags & (VM_READ | VM_EXEC))) 231c37ddd93SSam Ravnborg goto bad_area; 232c37ddd93SSam Ravnborg } 233c37ddd93SSam Ravnborg 234759496baSJohannes Weiner if (from_user) 235759496baSJohannes Weiner flags |= FAULT_FLAG_USER; 236759496baSJohannes Weiner if (write) 237759496baSJohannes Weiner flags |= FAULT_FLAG_WRITE; 238759496baSJohannes Weiner 239c37ddd93SSam Ravnborg /* 240c37ddd93SSam Ravnborg * If for any reason at all we couldn't handle the fault, 241c37ddd93SSam Ravnborg * make sure we exit gracefully rather than endlessly redo 242c37ddd93SSam Ravnborg * the fault. 243c37ddd93SSam Ravnborg */ 244dcddffd4SKirill A. Shutemov fault = handle_mm_fault(vma, address, flags); 245c29554f5SKautuk Consul 246c29554f5SKautuk Consul if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) 247c29554f5SKautuk Consul return; 248c29554f5SKautuk Consul 249c37ddd93SSam Ravnborg if (unlikely(fault & VM_FAULT_ERROR)) { 250c37ddd93SSam Ravnborg if (fault & VM_FAULT_OOM) 251c37ddd93SSam Ravnborg goto out_of_memory; 25233692f27SLinus Torvalds else if (fault & VM_FAULT_SIGSEGV) 25333692f27SLinus Torvalds goto bad_area; 254c37ddd93SSam Ravnborg else if (fault & VM_FAULT_SIGBUS) 255c37ddd93SSam Ravnborg goto do_sigbus; 256c37ddd93SSam Ravnborg BUG(); 257c37ddd93SSam Ravnborg } 258c29554f5SKautuk Consul 259c29554f5SKautuk Consul if (flags & FAULT_FLAG_ALLOW_RETRY) { 260a084b667SDavid S. Miller if (fault & VM_FAULT_MAJOR) { 261c37ddd93SSam Ravnborg current->maj_flt++; 262c29554f5SKautuk Consul perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 263c29554f5SKautuk Consul 1, regs, address); 264a084b667SDavid S. Miller } else { 265c37ddd93SSam Ravnborg current->min_flt++; 266c29554f5SKautuk Consul perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 267c29554f5SKautuk Consul 1, regs, address); 268a084b667SDavid S. Miller } 269c29554f5SKautuk Consul if (fault & VM_FAULT_RETRY) { 270c29554f5SKautuk Consul flags &= ~FAULT_FLAG_ALLOW_RETRY; 27145cac65bSShaohua Li flags |= FAULT_FLAG_TRIED; 272c29554f5SKautuk Consul 273c29554f5SKautuk Consul /* No need to up_read(&mm->mmap_sem) as we would 274c29554f5SKautuk Consul * have already released it in __lock_page_or_retry 275c29554f5SKautuk Consul * in mm/filemap.c. 276c29554f5SKautuk Consul */ 277c29554f5SKautuk Consul 278c29554f5SKautuk Consul goto retry; 279c29554f5SKautuk Consul } 280c29554f5SKautuk Consul } 281c29554f5SKautuk Consul 282c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 283c37ddd93SSam Ravnborg return; 284c37ddd93SSam Ravnborg 285c37ddd93SSam Ravnborg /* 286c37ddd93SSam Ravnborg * Something tried to access memory that isn't in our memory map.. 287c37ddd93SSam Ravnborg * Fix it, but check if it's kernel or user first.. 288c37ddd93SSam Ravnborg */ 289c37ddd93SSam Ravnborg bad_area: 290c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 291c37ddd93SSam Ravnborg 292c37ddd93SSam Ravnborg bad_area_nosemaphore: 293c37ddd93SSam Ravnborg /* User mode accesses just cause a SIGSEGV */ 294c37ddd93SSam Ravnborg if (from_user) { 2954b177647SDavid S. Miller do_fault_siginfo(code, SIGSEGV, regs, text_fault); 296c37ddd93SSam Ravnborg return; 297c37ddd93SSam Ravnborg } 298c37ddd93SSam Ravnborg 299c37ddd93SSam Ravnborg /* Is this in ex_table? */ 300c37ddd93SSam Ravnborg no_context: 301c37ddd93SSam Ravnborg g2 = regs->u_regs[UREG_G2]; 3020157141aSSam Ravnborg if (!from_user) { 3030157141aSSam Ravnborg fixup = search_extables_range(regs->pc, &g2); 30470168dfaSSam Ravnborg /* Values below 10 are reserved for other things */ 30570168dfaSSam Ravnborg if (fixup > 10) { 3069ef595d8SJoe Perches extern const unsigned int __memset_start[]; 3079ef595d8SJoe Perches extern const unsigned int __memset_end[]; 3089ef595d8SJoe Perches extern const unsigned int __csum_partial_copy_start[]; 3099ef595d8SJoe Perches extern const unsigned int __csum_partial_copy_end[]; 310c37ddd93SSam Ravnborg 311c37ddd93SSam Ravnborg #ifdef DEBUG_EXCEPTIONS 31270168dfaSSam Ravnborg printk("Exception: PC<%08lx> faddr<%08lx>\n", 31370168dfaSSam Ravnborg regs->pc, address); 314c37ddd93SSam Ravnborg printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n", 315c37ddd93SSam Ravnborg regs->pc, fixup, g2); 316c37ddd93SSam Ravnborg #endif 317c37ddd93SSam Ravnborg if ((regs->pc >= (unsigned long)__memset_start && 318c37ddd93SSam Ravnborg regs->pc < (unsigned long)__memset_end) || 319c37ddd93SSam Ravnborg (regs->pc >= (unsigned long)__csum_partial_copy_start && 320c37ddd93SSam Ravnborg regs->pc < (unsigned long)__csum_partial_copy_end)) { 321c37ddd93SSam Ravnborg regs->u_regs[UREG_I4] = address; 322c37ddd93SSam Ravnborg regs->u_regs[UREG_I5] = regs->pc; 323c37ddd93SSam Ravnborg } 324c37ddd93SSam Ravnborg regs->u_regs[UREG_G2] = g2; 325c37ddd93SSam Ravnborg regs->pc = fixup; 326c37ddd93SSam Ravnborg regs->npc = regs->pc + 4; 327c37ddd93SSam Ravnborg return; 328c37ddd93SSam Ravnborg } 329c37ddd93SSam Ravnborg } 330c37ddd93SSam Ravnborg 331c37ddd93SSam Ravnborg unhandled_fault(address, tsk, regs); 332c37ddd93SSam Ravnborg do_exit(SIGKILL); 333c37ddd93SSam Ravnborg 334c37ddd93SSam Ravnborg /* 335c37ddd93SSam Ravnborg * We ran out of memory, or some other thing happened to us that made 336c37ddd93SSam Ravnborg * us unable to handle the page fault gracefully. 337c37ddd93SSam Ravnborg */ 338c37ddd93SSam Ravnborg out_of_memory: 339c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 340a923c28fSDavid S. Miller if (from_user) { 341a923c28fSDavid S. Miller pagefault_out_of_memory(); 342a923c28fSDavid S. Miller return; 343a923c28fSDavid S. Miller } 344c37ddd93SSam Ravnborg goto no_context; 345c37ddd93SSam Ravnborg 346c37ddd93SSam Ravnborg do_sigbus: 347c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 3484b177647SDavid S. Miller do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, text_fault); 349c37ddd93SSam Ravnborg if (!from_user) 350c37ddd93SSam Ravnborg goto no_context; 351c37ddd93SSam Ravnborg 352c37ddd93SSam Ravnborg vmalloc_fault: 353c37ddd93SSam Ravnborg { 354c37ddd93SSam Ravnborg /* 355c37ddd93SSam Ravnborg * Synchronize this task's top level page-table 356c37ddd93SSam Ravnborg * with the 'reference' page table. 357c37ddd93SSam Ravnborg */ 358c37ddd93SSam Ravnborg int offset = pgd_index(address); 359c37ddd93SSam Ravnborg pgd_t *pgd, *pgd_k; 360c37ddd93SSam Ravnborg pmd_t *pmd, *pmd_k; 361c37ddd93SSam Ravnborg 362c37ddd93SSam Ravnborg pgd = tsk->active_mm->pgd + offset; 363c37ddd93SSam Ravnborg pgd_k = init_mm.pgd + offset; 364c37ddd93SSam Ravnborg 365c37ddd93SSam Ravnborg if (!pgd_present(*pgd)) { 366c37ddd93SSam Ravnborg if (!pgd_present(*pgd_k)) 367c37ddd93SSam Ravnborg goto bad_area_nosemaphore; 368c37ddd93SSam Ravnborg pgd_val(*pgd) = pgd_val(*pgd_k); 369c37ddd93SSam Ravnborg return; 370c37ddd93SSam Ravnborg } 371c37ddd93SSam Ravnborg 372c37ddd93SSam Ravnborg pmd = pmd_offset(pgd, address); 373c37ddd93SSam Ravnborg pmd_k = pmd_offset(pgd_k, address); 374c37ddd93SSam Ravnborg 375c37ddd93SSam Ravnborg if (pmd_present(*pmd) || !pmd_present(*pmd_k)) 376c37ddd93SSam Ravnborg goto bad_area_nosemaphore; 37770168dfaSSam Ravnborg 378c37ddd93SSam Ravnborg *pmd = *pmd_k; 379c37ddd93SSam Ravnborg return; 380c37ddd93SSam Ravnborg } 381c37ddd93SSam Ravnborg } 382c37ddd93SSam Ravnborg 383c37ddd93SSam Ravnborg /* This always deals with user addresses. */ 384c37ddd93SSam Ravnborg static void force_user_fault(unsigned long address, int write) 385c37ddd93SSam Ravnborg { 386c37ddd93SSam Ravnborg struct vm_area_struct *vma; 387c37ddd93SSam Ravnborg struct task_struct *tsk = current; 388c37ddd93SSam Ravnborg struct mm_struct *mm = tsk->mm; 389759496baSJohannes Weiner unsigned int flags = FAULT_FLAG_USER; 3904b177647SDavid S. Miller int code; 391c37ddd93SSam Ravnborg 3924b177647SDavid S. Miller code = SEGV_MAPERR; 393c37ddd93SSam Ravnborg 394c37ddd93SSam Ravnborg down_read(&mm->mmap_sem); 395c37ddd93SSam Ravnborg vma = find_vma(mm, address); 396c37ddd93SSam Ravnborg if (!vma) 397c37ddd93SSam Ravnborg goto bad_area; 398c37ddd93SSam Ravnborg if (vma->vm_start <= address) 399c37ddd93SSam Ravnborg goto good_area; 400c37ddd93SSam Ravnborg if (!(vma->vm_flags & VM_GROWSDOWN)) 401c37ddd93SSam Ravnborg goto bad_area; 402c37ddd93SSam Ravnborg if (expand_stack(vma, address)) 403c37ddd93SSam Ravnborg goto bad_area; 404c37ddd93SSam Ravnborg good_area: 4054b177647SDavid S. Miller code = SEGV_ACCERR; 406c37ddd93SSam Ravnborg if (write) { 407c37ddd93SSam Ravnborg if (!(vma->vm_flags & VM_WRITE)) 408c37ddd93SSam Ravnborg goto bad_area; 409759496baSJohannes Weiner flags |= FAULT_FLAG_WRITE; 410c37ddd93SSam Ravnborg } else { 411c37ddd93SSam Ravnborg if (!(vma->vm_flags & (VM_READ | VM_EXEC))) 412c37ddd93SSam Ravnborg goto bad_area; 413c37ddd93SSam Ravnborg } 414dcddffd4SKirill A. Shutemov switch (handle_mm_fault(vma, address, flags)) { 415c37ddd93SSam Ravnborg case VM_FAULT_SIGBUS: 416c37ddd93SSam Ravnborg case VM_FAULT_OOM: 417c37ddd93SSam Ravnborg goto do_sigbus; 418c37ddd93SSam Ravnborg } 419c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 420c37ddd93SSam Ravnborg return; 421c37ddd93SSam Ravnborg bad_area: 422c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 4234b177647SDavid S. Miller __do_fault_siginfo(code, SIGSEGV, tsk->thread.kregs, address); 424c37ddd93SSam Ravnborg return; 425c37ddd93SSam Ravnborg 426c37ddd93SSam Ravnborg do_sigbus: 427c37ddd93SSam Ravnborg up_read(&mm->mmap_sem); 4284b177647SDavid S. Miller __do_fault_siginfo(BUS_ADRERR, SIGBUS, tsk->thread.kregs, address); 429c37ddd93SSam Ravnborg } 430c37ddd93SSam Ravnborg 4319088333eSDavid S. Miller static void check_stack_aligned(unsigned long sp) 4329088333eSDavid S. Miller { 4339088333eSDavid S. Miller if (sp & 0x7UL) 4349088333eSDavid S. Miller force_sig(SIGILL, current); 4359088333eSDavid S. Miller } 4369088333eSDavid S. Miller 437c37ddd93SSam Ravnborg void window_overflow_fault(void) 438c37ddd93SSam Ravnborg { 439c37ddd93SSam Ravnborg unsigned long sp; 440c37ddd93SSam Ravnborg 441c37ddd93SSam Ravnborg sp = current_thread_info()->rwbuf_stkptrs[0]; 442c37ddd93SSam Ravnborg if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) 443c37ddd93SSam Ravnborg force_user_fault(sp + 0x38, 1); 444c37ddd93SSam Ravnborg force_user_fault(sp, 1); 4459088333eSDavid S. Miller 4469088333eSDavid S. Miller check_stack_aligned(sp); 447c37ddd93SSam Ravnborg } 448c37ddd93SSam Ravnborg 449c37ddd93SSam Ravnborg void window_underflow_fault(unsigned long sp) 450c37ddd93SSam Ravnborg { 451c37ddd93SSam Ravnborg if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) 452c37ddd93SSam Ravnborg force_user_fault(sp + 0x38, 0); 453c37ddd93SSam Ravnborg force_user_fault(sp, 0); 4549088333eSDavid S. Miller 4559088333eSDavid S. Miller check_stack_aligned(sp); 456c37ddd93SSam Ravnborg } 457c37ddd93SSam Ravnborg 458c37ddd93SSam Ravnborg void window_ret_fault(struct pt_regs *regs) 459c37ddd93SSam Ravnborg { 460c37ddd93SSam Ravnborg unsigned long sp; 461c37ddd93SSam Ravnborg 462c37ddd93SSam Ravnborg sp = regs->u_regs[UREG_FP]; 463c37ddd93SSam Ravnborg if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) 464c37ddd93SSam Ravnborg force_user_fault(sp + 0x38, 0); 465c37ddd93SSam Ravnborg force_user_fault(sp, 0); 4669088333eSDavid S. Miller 4679088333eSDavid S. Miller check_stack_aligned(sp); 468c37ddd93SSam Ravnborg } 469