linux/arch/m68k/mm/fault.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/m68k/mm/fault.c
   3 *
   4 *  Copyright (C) 1995  Hamish Macdonald
   5 */
   6
   7#include <linux/mman.h>
   8#include <linux/mm.h>
   9#include <linux/kernel.h>
  10#include <linux/ptrace.h>
  11#include <linux/interrupt.h>
  12#include <linux/module.h>
  13
  14#include <asm/setup.h>
  15#include <asm/traps.h>
  16#include <asm/system.h>
  17#include <asm/uaccess.h>
  18#include <asm/pgalloc.h>
  19
  20extern void die_if_kernel(char *, struct pt_regs *, long);
  21extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */
  22
  23int send_fault_sig(struct pt_regs *regs)
  24{
  25        siginfo_t siginfo = { 0, 0, 0, };
  26
  27        siginfo.si_signo = current->thread.signo;
  28        siginfo.si_code = current->thread.code;
  29        siginfo.si_addr = (void *)current->thread.faddr;
  30#ifdef DEBUG
  31        printk("send_fault_sig: %p,%d,%d\n", siginfo.si_addr, siginfo.si_signo, siginfo.si_code);
  32#endif
  33
  34        if (user_mode(regs)) {
  35                force_sig_info(siginfo.si_signo,
  36                               &siginfo, current);
  37        } else {
  38                const struct exception_table_entry *fixup;
  39
  40                /* Are we prepared to handle this kernel fault? */
  41                if ((fixup = search_exception_tables(regs->pc))) {
  42                        struct pt_regs *tregs;
  43                        /* Create a new four word stack frame, discarding the old
  44                           one.  */
  45                        regs->stkadj = frame_extra_sizes[regs->format];
  46                        tregs = (struct pt_regs *)((ulong)regs + regs->stkadj);
  47                        tregs->vector = regs->vector;
  48                        tregs->format = 0;
  49                        tregs->pc = fixup->fixup;
  50                        tregs->sr = regs->sr;
  51                        return -1;
  52                }
  53
  54                //if (siginfo.si_signo == SIGBUS)
  55                //      force_sig_info(siginfo.si_signo,
  56                //                     &siginfo, current);
  57
  58                /*
  59                 * Oops. The kernel tried to access some bad page. We'll have to
  60                 * terminate things with extreme prejudice.
  61                 */
  62                if ((unsigned long)siginfo.si_addr < PAGE_SIZE)
  63                        printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
  64                else
  65                        printk(KERN_ALERT "Unable to handle kernel access");
  66                printk(" at virtual address %p\n", siginfo.si_addr);
  67                die_if_kernel("Oops", regs, 0 /*error_code*/);
  68                do_exit(SIGKILL);
  69        }
  70
  71        return 1;
  72}
  73
  74/*
  75 * This routine handles page faults.  It determines the problem, and
  76 * then passes it off to one of the appropriate routines.
  77 *
  78 * error_code:
  79 *      bit 0 == 0 means no page found, 1 means protection fault
  80 *      bit 1 == 0 means read, 1 means write
  81 *
  82 * If this routine detects a bad access, it returns 1, otherwise it
  83 * returns 0.
  84 */
  85int do_page_fault(struct pt_regs *regs, unsigned long address,
  86                              unsigned long error_code)
  87{
  88        struct mm_struct *mm = current->mm;
  89        struct vm_area_struct * vma;
  90        int write, fault;
  91
  92#ifdef DEBUG
  93        printk ("do page fault:\nregs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
  94                regs->sr, regs->pc, address, error_code,
  95                current->mm->pgd);
  96#endif
  97
  98        /*
  99         * If we're in an interrupt or have no user
 100         * context, we must not take the fault..
 101         */
 102        if (in_atomic() || !mm)
 103                goto no_context;
 104
 105        down_read(&mm->mmap_sem);
 106
 107        vma = find_vma(mm, address);
 108        if (!vma)
 109                goto map_err;
 110        if (vma->vm_flags & VM_IO)
 111                goto acc_err;
 112        if (vma->vm_start <= address)
 113                goto good_area;
 114        if (!(vma->vm_flags & VM_GROWSDOWN))
 115                goto map_err;
 116        if (user_mode(regs)) {
 117                /* Accessing the stack below usp is always a bug.  The
 118                   "+ 256" is there due to some instructions doing
 119                   pre-decrement on the stack and that doesn't show up
 120                   until later.  */
 121                if (address + 256 < rdusp())
 122                        goto map_err;
 123        }
 124        if (expand_stack(vma, address))
 125                goto map_err;
 126
 127/*
 128 * Ok, we have a good vm_area for this memory access, so
 129 * we can handle it..
 130 */
 131good_area:
 132#ifdef DEBUG
 133        printk("do_page_fault: good_area\n");
 134#endif
 135        write = 0;
 136        switch (error_code & 3) {
 137                default:        /* 3: write, present */
 138                        /* fall through */
 139                case 2:         /* write, not present */
 140                        if (!(vma->vm_flags & VM_WRITE))
 141                                goto acc_err;
 142                        write++;
 143                        break;
 144                case 1:         /* read, present */
 145                        goto acc_err;
 146                case 0:         /* read, not present */
 147                        if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
 148                                goto acc_err;
 149        }
 150
 151        /*
 152         * If for any reason at all we couldn't handle the fault,
 153         * make sure we exit gracefully rather than endlessly redo
 154         * the fault.
 155         */
 156
 157 survive:
 158        fault = handle_mm_fault(mm, vma, address, write);
 159#ifdef DEBUG
 160        printk("handle_mm_fault returns %d\n",fault);
 161#endif
 162        if (unlikely(fault & VM_FAULT_ERROR)) {
 163                if (fault & VM_FAULT_OOM)
 164                        goto out_of_memory;
 165                else if (fault & VM_FAULT_SIGBUS)
 166                        goto bus_err;
 167                BUG();
 168        }
 169        if (fault & VM_FAULT_MAJOR)
 170                current->maj_flt++;
 171        else
 172                current->min_flt++;
 173
 174        up_read(&mm->mmap_sem);
 175        return 0;
 176
 177/*
 178 * We ran out of memory, or some other thing happened to us that made
 179 * us unable to handle the page fault gracefully.
 180 */
 181out_of_memory:
 182        up_read(&mm->mmap_sem);
 183        if (is_global_init(current)) {
 184                yield();
 185                down_read(&mm->mmap_sem);
 186                goto survive;
 187        }
 188
 189        printk("VM: killing process %s\n", current->comm);
 190        if (user_mode(regs))
 191                do_group_exit(SIGKILL);
 192
 193no_context:
 194        current->thread.signo = SIGBUS;
 195        current->thread.faddr = address;
 196        return send_fault_sig(regs);
 197
 198bus_err:
 199        current->thread.signo = SIGBUS;
 200        current->thread.code = BUS_ADRERR;
 201        current->thread.faddr = address;
 202        goto send_sig;
 203
 204map_err:
 205        current->thread.signo = SIGSEGV;
 206        current->thread.code = SEGV_MAPERR;
 207        current->thread.faddr = address;
 208        goto send_sig;
 209
 210acc_err:
 211        current->thread.signo = SIGSEGV;
 212        current->thread.code = SEGV_ACCERR;
 213        current->thread.faddr = address;
 214
 215send_sig:
 216        up_read(&mm->mmap_sem);
 217        return send_fault_sig(regs);
 218}
 219