1fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta/* Page Fault Handling for ARC (TLB Miss / ProtV) 2fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * 3fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 4fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * 5fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * This program is free software; you can redistribute it and/or modify 6fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * it under the terms of the GNU General Public License version 2 as 7fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * published by the Free Software Foundation. 8fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta */ 9fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 10fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta#include <linux/signal.h> 11fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta#include <linux/interrupt.h> 12fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta#include <linux/sched.h> 13fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta#include <linux/errno.h> 14fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta#include <linux/ptrace.h> 15fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta#include <linux/uaccess.h> 16fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta#include <linux/kdebug.h> 17fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta#include <asm/pgalloc.h> 18da1677b02d3ef674dfd8a4ba1ed32153dc717fa2Vineet Gupta#include <asm/mmu.h> 19fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 209c41f4eeb9d51f3ece20428d35a3ea32cf3b5622Vineet Guptastatic int handle_vmalloc_fault(unsigned long address) 21fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta{ 22fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* 23fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * Synchronize this task's top level page-table 24fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * with the 'reference' page table. 25fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta */ 26fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta pgd_t *pgd, *pgd_k; 27fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta pud_t *pud, *pud_k; 28fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta pmd_t *pmd, *pmd_k; 29fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 309c41f4eeb9d51f3ece20428d35a3ea32cf3b5622Vineet Gupta pgd = pgd_offset_fast(current->active_mm, address); 31fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta pgd_k = pgd_offset_k(address); 32fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 33fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (!pgd_present(*pgd_k)) 34fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto bad_area; 35fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 36fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta pud = pud_offset(pgd, address); 37fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta pud_k = pud_offset(pgd_k, address); 38fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (!pud_present(*pud_k)) 39fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto bad_area; 40fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 41fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta pmd = pmd_offset(pud, address); 42fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta pmd_k = pmd_offset(pud_k, address); 43fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (!pmd_present(*pmd_k)) 44fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto bad_area; 45fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 46fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta set_pmd(pmd, *pmd_k); 47fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 48fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* XXX: create the TLB entry here */ 49fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta return 0; 50fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 51fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Guptabad_area: 52fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta return 1; 53fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta} 54fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 5521a63b56044706aa37637315dd27d9d465bbd5c4Vineet Guptavoid do_page_fault(unsigned long address, struct pt_regs *regs) 56fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta{ 57fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta struct vm_area_struct *vma = NULL; 58fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta struct task_struct *tsk = current; 59fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta struct mm_struct *mm = tsk->mm; 60fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta siginfo_t info; 61fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta int fault, ret; 6238a9ff6d247cf9afcbe55ea245b650b8955029fdVineet Gupta int write = regs->ecr_cause & ECR_C_PROTV_STORE; /* ST/EX */ 63759496ba6407c6994d6a5ce3a5e74937d7816208Johannes Weiner unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; 64fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 65fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* 66fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * We fault-in kernel-space virtual memory on-demand. The 67fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * 'reference' page table is init_mm.pgd. 68fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * 69fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * NOTE! We MUST NOT take any locks for this case. We may 70fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * be in an interrupt or a critical region, and should 71fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * only copy the information from the master page table, 72fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * nothing more. 73fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta */ 74fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (address >= VMALLOC_START && address <= VMALLOC_END) { 759c41f4eeb9d51f3ece20428d35a3ea32cf3b5622Vineet Gupta ret = handle_vmalloc_fault(address); 76fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (unlikely(ret)) 77fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto bad_area_nosemaphore; 78fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta else 79fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta return; 80fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta } 81fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 82fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta info.si_code = SEGV_MAPERR; 83fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 84fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* 85fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * If we're in an interrupt or have no user 86fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * context, we must not take the fault.. 87fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta */ 88fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (in_atomic() || !mm) 89fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto no_context; 90fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 91759496ba6407c6994d6a5ce3a5e74937d7816208Johannes Weiner if (user_mode(regs)) 92759496ba6407c6994d6a5ce3a5e74937d7816208Johannes Weiner flags |= FAULT_FLAG_USER; 93fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Guptaretry: 94fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta down_read(&mm->mmap_sem); 95fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta vma = find_vma(mm, address); 96fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (!vma) 97fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto bad_area; 98fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (vma->vm_start <= address) 99fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto good_area; 100fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (!(vma->vm_flags & VM_GROWSDOWN)) 101fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto bad_area; 102fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (expand_stack(vma, address)) 103fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto bad_area; 104fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 105fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* 106fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * Ok, we have a good vm_area for this memory access, so 107fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * we can handle it.. 108fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta */ 109fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Guptagood_area: 110fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta info.si_code = SEGV_ACCERR; 111fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 112fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* Handle protection violation, execute on heap or stack */ 113fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 11438a9ff6d247cf9afcbe55ea245b650b8955029fdVineet Gupta if ((regs->ecr_vec == ECR_V_PROTV) && 11538a9ff6d247cf9afcbe55ea245b650b8955029fdVineet Gupta (regs->ecr_cause == ECR_C_PROTV_INST_FETCH)) 116fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto bad_area; 117fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 118fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (write) { 119fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (!(vma->vm_flags & VM_WRITE)) 120fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto bad_area; 121759496ba6407c6994d6a5ce3a5e74937d7816208Johannes Weiner flags |= FAULT_FLAG_WRITE; 122fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta } else { 123fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (!(vma->vm_flags & (VM_READ | VM_EXEC))) 124fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto bad_area; 125fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta } 126fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 127fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* 128fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * If for any reason at all we couldn't handle the fault, 129fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * make sure we exit gracefully rather than endlessly redo 130fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * the fault. 131fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta */ 132fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta fault = handle_mm_fault(mm, vma, address, flags); 133fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 134fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* If Pagefault was interrupted by SIGKILL, exit page fault "early" */ 135fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (unlikely(fatal_signal_pending(current))) { 136fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if ((fault & VM_FAULT_ERROR) && !(fault & VM_FAULT_RETRY)) 137fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta up_read(&mm->mmap_sem); 138fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (user_mode(regs)) 139fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta return; 140fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta } 141fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 142fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (likely(!(fault & VM_FAULT_ERROR))) { 143fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (flags & FAULT_FLAG_ALLOW_RETRY) { 144fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* To avoid updating stats twice for retry case */ 145fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (fault & VM_FAULT_MAJOR) 146fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta tsk->maj_flt++; 147fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta else 148fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta tsk->min_flt++; 149fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 150fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (fault & VM_FAULT_RETRY) { 151fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta flags &= ~FAULT_FLAG_ALLOW_RETRY; 152fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta flags |= FAULT_FLAG_TRIED; 153fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto retry; 154fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta } 155fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta } 156fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 157fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* Fault Handled Gracefully */ 158fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta up_read(&mm->mmap_sem); 159fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta return; 160fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta } 161fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 162fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (fault & VM_FAULT_OOM) 163fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto out_of_memory; 164fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta else if (fault & VM_FAULT_SIGBUS) 165fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto do_sigbus; 166fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 167fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* no man's land */ 168fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta BUG(); 169fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 170fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* 171fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * Something tried to access memory that isn't in our memory map.. 172fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * Fix it, but check if it's kernel or user first.. 173fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta */ 174fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Guptabad_area: 175fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta up_read(&mm->mmap_sem); 176fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 177fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Guptabad_area_nosemaphore: 178fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* User mode accesses just cause a SIGSEGV */ 179fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (user_mode(regs)) { 180fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta tsk->thread.fault_address = address; 181fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta info.si_signo = SIGSEGV; 182fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta info.si_errno = 0; 183fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* info.si_code has been set above */ 184fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta info.si_addr = (void __user *)address; 185fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta force_sig_info(SIGSEGV, &info, tsk); 186fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta return; 187fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta } 188fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 189fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Guptano_context: 190fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta /* Are we prepared to handle this kernel fault? 191fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * 192fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * (The kernel has valid exception-points in the source 193fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * when it acesses user-memory. When it fails in one 194fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * of those points, we find it in a table and do a jump 195fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * to some fixup code that loads an appropriate error 196fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta * code) 197fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta */ 198fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (fixup_exception(regs)) 199fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta return; 200fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 20138a9ff6d247cf9afcbe55ea245b650b8955029fdVineet Gupta die("Oops", regs, address); 202fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 203fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Guptaout_of_memory: 204fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta up_read(&mm->mmap_sem); 205fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 206609838cfed972d49a65aac7923a9ff5cbe482e30Johannes Weiner if (user_mode(regs)) { 207609838cfed972d49a65aac7923a9ff5cbe482e30Johannes Weiner pagefault_out_of_memory(); 208609838cfed972d49a65aac7923a9ff5cbe482e30Johannes Weiner return; 209609838cfed972d49a65aac7923a9ff5cbe482e30Johannes Weiner } 210fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 211fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto no_context; 212fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 213fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Guptado_sigbus: 214fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta up_read(&mm->mmap_sem); 215fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 216fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta if (!user_mode(regs)) 217fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta goto no_context; 218fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta 219fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta tsk->thread.fault_address = address; 220fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta info.si_signo = SIGBUS; 221fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta info.si_errno = 0; 222fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta info.si_code = BUS_ADRERR; 223fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta info.si_addr = (void __user *)address; 224fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta force_sig_info(SIGBUS, &info, tsk); 225fbd7053a7854b12b0fdc415089c59baabf25c625Vineet Gupta} 226