linux/arch/cris/mm/fault.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/cris/mm/fault.c
   3 *
   4 *  Copyright (C) 2000-2006  Axis Communications AB
   5 *
   6 *  Authors:  Bjorn Wesen
   7 *
   8 */
   9
  10#include <linux/mm.h>
  11#include <linux/interrupt.h>
  12#include <linux/module.h>
  13#include <asm/uaccess.h>
  14
  15extern int find_fixup_code(struct pt_regs *);
  16extern void die_if_kernel(const char *, struct pt_regs *, long);
  17
  18/* debug of low-level TLB reload */
  19#undef DEBUG
  20
  21#ifdef DEBUG
  22#define D(x) x
  23#else
  24#define D(x)
  25#endif
  26
  27/* debug of higher-level faults */
  28#define DPG(x)
  29
  30/* current active page directory */
  31
  32volatile DEFINE_PER_CPU(pgd_t *,current_pgd);
  33unsigned long cris_signal_return_page;
  34
  35/*
  36 * This routine handles page faults.  It determines the address,
  37 * and the problem, and then passes it off to one of the appropriate
  38 * routines.
  39 *
  40 * Notice that the address we're given is aligned to the page the fault
  41 * occurred in, since we only get the PFN in R_MMU_CAUSE not the complete
  42 * address.
  43 *
  44 * error_code:
  45 *      bit 0 == 0 means no page found, 1 means protection fault
  46 *      bit 1 == 0 means read, 1 means write
  47 *
  48 * If this routine detects a bad access, it returns 1, otherwise it
  49 * returns 0.
  50 */
  51
  52asmlinkage void
  53do_page_fault(unsigned long address, struct pt_regs *regs,
  54              int protection, int writeaccess)
  55{
  56        struct task_struct *tsk;
  57        struct mm_struct *mm;
  58        struct vm_area_struct * vma;
  59        siginfo_t info;
  60        int fault;
  61
  62        D(printk(KERN_DEBUG
  63                 "Page fault for %lX on %X at %lX, prot %d write %d\n",
  64                 address, smp_processor_id(), instruction_pointer(regs),
  65                 protection, writeaccess));
  66
  67        tsk = current;
  68
  69        /*
  70         * We fault-in kernel-space virtual memory on-demand. The
  71         * 'reference' page table is init_mm.pgd.
  72         *
  73         * NOTE! We MUST NOT take any locks for this case. We may
  74         * be in an interrupt or a critical region, and should
  75         * only copy the information from the master page table,
  76         * nothing more.
  77         *
  78         * NOTE2: This is done so that, when updating the vmalloc
  79         * mappings we don't have to walk all processes pgdirs and
  80         * add the high mappings all at once. Instead we do it as they
  81         * are used. However vmalloc'ed page entries have the PAGE_GLOBAL
  82         * bit set so sometimes the TLB can use a lingering entry.
  83         *
  84         * This verifies that the fault happens in kernel space
  85         * and that the fault was not a protection error (error_code & 1).
  86         */
  87
  88        if (address >= VMALLOC_START &&
  89            !protection &&
  90            !user_mode(regs))
  91                goto vmalloc_fault;
  92
  93        /* When stack execution is not allowed we store the signal
  94         * trampolines in the reserved cris_signal_return_page.
  95         * Handle this in the exact same way as vmalloc (we know
  96         * that the mapping is there and is valid so no need to
  97         * call handle_mm_fault).
  98         */
  99        if (cris_signal_return_page &&
 100            address == cris_signal_return_page &&
 101            !protection && user_mode(regs))
 102                goto vmalloc_fault;
 103
 104        /* we can and should enable interrupts at this point */
 105        local_irq_enable();
 106
 107        mm = tsk->mm;
 108        info.si_code = SEGV_MAPERR;
 109
 110        /*
 111         * If we're in an interrupt or have no user
 112         * context, we must not take the fault..
 113         */
 114
 115        if (in_interrupt() || !mm)
 116                goto no_context;
 117
 118        down_read(&mm->mmap_sem);
 119        vma = find_vma(mm, address);
 120        if (!vma)
 121                goto bad_area;
 122        if (vma->vm_start <= address)
 123                goto good_area;
 124        if (!(vma->vm_flags & VM_GROWSDOWN))
 125                goto bad_area;
 126        if (user_mode(regs)) {
 127                /*
 128                 * accessing the stack below usp is always a bug.
 129                 * we get page-aligned addresses so we can only check
 130                 * if we're within a page from usp, but that might be
 131                 * enough to catch brutal errors at least.
 132                 */
 133                if (address + PAGE_SIZE < rdusp())
 134                        goto bad_area;
 135        }
 136        if (expand_stack(vma, address))
 137                goto bad_area;
 138
 139        /*
 140         * Ok, we have a good vm_area for this memory access, so
 141         * we can handle it..
 142         */
 143
 144 good_area:
 145        info.si_code = SEGV_ACCERR;
 146
 147        /* first do some preliminary protection checks */
 148
 149        if (writeaccess == 2){
 150                if (!(vma->vm_flags & VM_EXEC))
 151                        goto bad_area;
 152        } else if (writeaccess == 1) {
 153                if (!(vma->vm_flags & VM_WRITE))
 154                        goto bad_area;
 155        } else {
 156                if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 157                        goto bad_area;
 158        }
 159
 160        /*
 161         * If for any reason at all we couldn't handle the fault,
 162         * make sure we exit gracefully rather than endlessly redo
 163         * the fault.
 164         */
 165
 166        fault = handle_mm_fault(mm, vma, address, writeaccess & 1);
 167        if (unlikely(fault & VM_FAULT_ERROR)) {
 168                if (fault & VM_FAULT_OOM)
 169                        goto out_of_memory;
 170                else if (fault & VM_FAULT_SIGBUS)
 171                        goto do_sigbus;
 172                BUG();
 173        }
 174        if (fault & VM_FAULT_MAJOR)
 175                tsk->maj_flt++;
 176        else
 177                tsk->min_flt++;
 178
 179        up_read(&mm->mmap_sem);
 180        return;
 181
 182        /*
 183         * Something tried to access memory that isn't in our memory map..
 184         * Fix it, but check if it's kernel or user first..
 185         */
 186
 187 bad_area:
 188        up_read(&mm->mmap_sem);
 189
 190 bad_area_nosemaphore:
 191        DPG(show_registers(regs));
 192
 193        /* User mode accesses just cause a SIGSEGV */
 194
 195        if (user_mode(regs)) {
 196                info.si_signo = SIGSEGV;
 197                info.si_errno = 0;
 198                /* info.si_code has been set above */
 199                info.si_addr = (void *)address;
 200                force_sig_info(SIGSEGV, &info, tsk);
 201                printk(KERN_NOTICE "%s (pid %d) segfaults for page "
 202                       "address %08lx at pc %08lx\n",
 203                       tsk->comm, tsk->pid, address, instruction_pointer(regs));
 204                return;
 205        }
 206
 207 no_context:
 208
 209        /* Are we prepared to handle this kernel fault?
 210         *
 211         * (The kernel has valid exception-points in the source
 212         *  when it acesses user-memory. When it fails in one
 213         *  of those points, we find it in a table and do a jump
 214         *  to some fixup code that loads an appropriate error
 215         *  code)
 216         */
 217
 218        if (find_fixup_code(regs))
 219                return;
 220
 221        /*
 222         * Oops. The kernel tried to access some bad page. We'll have to
 223         * terminate things with extreme prejudice.
 224         */
 225
 226        if (!oops_in_progress) {
 227                oops_in_progress = 1;
 228                if ((unsigned long) (address) < PAGE_SIZE)
 229                        printk(KERN_ALERT "Unable to handle kernel NULL "
 230                                "pointer dereference");
 231                else
 232                        printk(KERN_ALERT "Unable to handle kernel access"
 233                                " at virtual address %08lx\n", address);
 234
 235                die_if_kernel("Oops", regs, (writeaccess << 1) | protection);
 236                oops_in_progress = 0;
 237        }
 238
 239        do_exit(SIGKILL);
 240
 241        /*
 242         * We ran out of memory, or some other thing happened to us that made
 243         * us unable to handle the page fault gracefully.
 244         */
 245
 246 out_of_memory:
 247        up_read(&mm->mmap_sem);
 248        printk("VM: killing process %s\n", tsk->comm);
 249        if (user_mode(regs))
 250                do_exit(SIGKILL);
 251        goto no_context;
 252
 253 do_sigbus:
 254        up_read(&mm->mmap_sem);
 255
 256        /*
 257         * Send a sigbus, regardless of whether we were in kernel
 258         * or user mode.
 259         */
 260        info.si_signo = SIGBUS;
 261        info.si_errno = 0;
 262        info.si_code = BUS_ADRERR;
 263        info.si_addr = (void *)address;
 264        force_sig_info(SIGBUS, &info, tsk);
 265
 266        /* Kernel mode? Handle exceptions or die */
 267        if (!user_mode(regs))
 268                goto no_context;
 269        return;
 270
 271vmalloc_fault:
 272        {
 273                /*
 274                 * Synchronize this task's top level page-table
 275                 * with the 'reference' page table.
 276                 *
 277                 * Use current_pgd instead of tsk->active_mm->pgd
 278                 * since the latter might be unavailable if this
 279                 * code is executed in a misfortunately run irq
 280                 * (like inside schedule() between switch_mm and
 281                 *  switch_to...).
 282                 */
 283
 284                int offset = pgd_index(address);
 285                pgd_t *pgd, *pgd_k;
 286                pud_t *pud, *pud_k;
 287                pmd_t *pmd, *pmd_k;
 288                pte_t *pte_k;
 289
 290                pgd = (pgd_t *)per_cpu(current_pgd, smp_processor_id()) + offset;
 291                pgd_k = init_mm.pgd + offset;
 292
 293                /* Since we're two-level, we don't need to do both
 294                 * set_pgd and set_pmd (they do the same thing). If
 295                 * we go three-level at some point, do the right thing
 296                 * with pgd_present and set_pgd here.
 297                 *
 298                 * Also, since the vmalloc area is global, we don't
 299                 * need to copy individual PTE's, it is enough to
 300                 * copy the pgd pointer into the pte page of the
 301                 * root task. If that is there, we'll find our pte if
 302                 * it exists.
 303                 */
 304
 305                pud = pud_offset(pgd, address);
 306                pud_k = pud_offset(pgd_k, address);
 307                if (!pud_present(*pud_k))
 308                        goto no_context;
 309
 310                pmd = pmd_offset(pud, address);
 311                pmd_k = pmd_offset(pud_k, address);
 312
 313                if (!pmd_present(*pmd_k))
 314                        goto bad_area_nosemaphore;
 315
 316                set_pmd(pmd, *pmd_k);
 317
 318                /* Make sure the actual PTE exists as well to
 319                 * catch kernel vmalloc-area accesses to non-mapped
 320                 * addresses. If we don't do this, this will just
 321                 * silently loop forever.
 322                 */
 323
 324                pte_k = pte_offset_kernel(pmd_k, address);
 325                if (!pte_present(*pte_k))
 326                        goto no_context;
 327
 328                return;
 329        }
 330}
 331
 332/* Find fixup code. */
 333int
 334find_fixup_code(struct pt_regs *regs)
 335{
 336        const struct exception_table_entry *fixup;
 337
 338        if ((fixup = search_exception_tables(instruction_pointer(regs))) != 0) {
 339                /* Adjust the instruction pointer in the stackframe. */
 340                instruction_pointer(regs) = fixup->fixup;
 341                arch_fixup(regs);
 342                return 1;
 343        }
 344
 345        return 0;
 346}
 347