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