The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arch/score/mm/fault.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * arch/score/mm/fault.c
    3  *
    4  * Score Processor version.
    5  *
    6  * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
    7  *  Lennox Wu <lennox.wu@sunplusct.com>
    8  *  Chen Liqin <liqin.chen@sunplusct.com>
    9  *
   10  * This program is free software; you can redistribute it and/or modify
   11  * it under the terms of the GNU General Public License as published by
   12  * the Free Software Foundation; either version 2 of the License, or
   13  * (at your option) any later version.
   14  *
   15  * This program is distributed in the hope that it will be useful,
   16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18  * GNU General Public License for more details.
   19  *
   20  * You should have received a copy of the GNU General Public License
   21  * along with this program; if not, see the file COPYING, or write
   22  * to the Free Software Foundation, Inc.,
   23  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   24  */
   25 
   26 #include <linux/errno.h>
   27 #include <linux/interrupt.h>
   28 #include <linux/kernel.h>
   29 #include <linux/mm.h>
   30 #include <linux/mman.h>
   31 #include <linux/module.h>
   32 #include <linux/signal.h>
   33 #include <linux/sched.h>
   34 #include <linux/string.h>
   35 #include <linux/types.h>
   36 #include <linux/ptrace.h>
   37 
   38 /*
   39  * This routine handles page faults.  It determines the address,
   40  * and the problem, and then passes it off to one of the appropriate
   41  * routines.
   42  */
   43 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
   44                                 unsigned long address)
   45 {
   46         struct vm_area_struct *vma = NULL;
   47         struct task_struct *tsk = current;
   48         struct mm_struct *mm = tsk->mm;
   49         const int field = sizeof(unsigned long) * 2;
   50         siginfo_t info;
   51         int fault;
   52 
   53         info.si_code = SEGV_MAPERR;
   54 
   55         /*
   56         * We fault-in kernel-space virtual memory on-demand. The
   57         * 'reference' page table is init_mm.pgd.
   58         *
   59         * NOTE! We MUST NOT take any locks for this case. We may
   60         * be in an interrupt or a critical region, and should
   61         * only copy the information from the master page table,
   62         * nothing more.
   63         */
   64         if (unlikely(address >= VMALLOC_START && address <= VMALLOC_END))
   65                 goto vmalloc_fault;
   66 #ifdef MODULE_START
   67         if (unlikely(address >= MODULE_START && address < MODULE_END))
   68                 goto vmalloc_fault;
   69 #endif
   70 
   71         /*
   72         * If we're in an interrupt or have no user
   73         * context, we must not take the fault..
   74         */
   75         if (in_atomic() || !mm)
   76                 goto bad_area_nosemaphore;
   77 
   78         down_read(&mm->mmap_sem);
   79         vma = find_vma(mm, address);
   80         if (!vma)
   81                 goto bad_area;
   82         if (vma->vm_start <= address)
   83                 goto good_area;
   84         if (!(vma->vm_flags & VM_GROWSDOWN))
   85                 goto bad_area;
   86         if (expand_stack(vma, address))
   87                 goto bad_area;
   88         /*
   89         * Ok, we have a good vm_area for this memory access, so
   90         * we can handle it..
   91          */
   92 good_area:
   93         info.si_code = SEGV_ACCERR;
   94 
   95         if (write) {
   96                 if (!(vma->vm_flags & VM_WRITE))
   97                         goto bad_area;
   98         } else {
   99                 if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)))
  100                         goto bad_area;
  101         }
  102 
  103 survive:
  104         /*
  105         * If for any reason at all we couldn't handle the fault,
  106         * make sure we exit gracefully rather than endlessly redo
  107         * the fault.
  108         */
  109         fault = handle_mm_fault(mm, vma, address, write);
  110         if (unlikely(fault & VM_FAULT_ERROR)) {
  111                 if (fault & VM_FAULT_OOM)
  112                         goto out_of_memory;
  113                 else if (fault & VM_FAULT_SIGBUS)
  114                         goto do_sigbus;
  115                 BUG();
  116         }
  117         if (fault & VM_FAULT_MAJOR)
  118                 tsk->maj_flt++;
  119         else
  120                 tsk->min_flt++;
  121 
  122         up_read(&mm->mmap_sem);
  123         return;
  124 
  125         /*
  126         * Something tried to access memory that isn't in our memory map..
  127         * Fix it, but check if it's kernel or user first..
  128          */
  129 bad_area:
  130         up_read(&mm->mmap_sem);
  131 
  132 bad_area_nosemaphore:
  133         /* User mode accesses just cause a SIGSEGV */
  134         if (user_mode(regs)) {
  135                 tsk->thread.cp0_badvaddr = address;
  136                 tsk->thread.error_code = write;
  137                 info.si_signo = SIGSEGV;
  138                 info.si_errno = 0;
  139                 /* info.si_code has been set above */
  140                 info.si_addr = (void __user *) address;
  141                 force_sig_info(SIGSEGV, &info, tsk);
  142                 return;
  143         }
  144 
  145 no_context:
  146         /* Are we prepared to handle this kernel fault? */
  147         if (fixup_exception(regs)) {
  148                 current->thread.cp0_baduaddr = address;
  149                 return;
  150         }
  151 
  152         /*
  153         * Oops. The kernel tried to access some bad page. We'll have to
  154         * terminate things with extreme prejudice.
  155         */
  156         bust_spinlocks(1);
  157 
  158         printk(KERN_ALERT "CPU %d Unable to handle kernel paging request at "
  159                         "virtual address %0*lx, epc == %0*lx, ra == %0*lx\n",
  160                         0, field, address, field, regs->cp0_epc,
  161                         field, regs->regs[3]);
  162         die("Oops", regs);
  163 
  164         /*
  165         * We ran out of memory, or some other thing happened to us that made
  166         * us unable to handle the page fault gracefully.
  167         */
  168 out_of_memory:
  169         up_read(&mm->mmap_sem);
  170         if (is_global_init(tsk)) {
  171                 yield();
  172                 down_read(&mm->mmap_sem);
  173                 goto survive;
  174         }
  175         printk("VM: killing process %s\n", tsk->comm);
  176         if (user_mode(regs))
  177                 do_group_exit(SIGKILL);
  178         goto no_context;
  179 
  180 do_sigbus:
  181         up_read(&mm->mmap_sem);
  182         /* Kernel mode? Handle exceptions or die */
  183         if (!user_mode(regs))
  184                 goto no_context;
  185         else
  186         /*
  187         * Send a sigbus, regardless of whether we were in kernel
  188         * or user mode.
  189         */
  190         tsk->thread.cp0_badvaddr = address;
  191         info.si_signo = SIGBUS;
  192         info.si_errno = 0;
  193         info.si_code = BUS_ADRERR;
  194         info.si_addr = (void __user *) address;
  195         force_sig_info(SIGBUS, &info, tsk);
  196         return;
  197 vmalloc_fault:
  198         {
  199                 /*
  200                 * Synchronize this task's top level page-table
  201                 * with the 'reference' page table.
  202                 *
  203                 * Do _not_ use "tsk" here. We might be inside
  204                 * an interrupt in the middle of a task switch..
  205                 */
  206                 int offset = __pgd_offset(address);
  207                 pgd_t *pgd, *pgd_k;
  208                 pud_t *pud, *pud_k;
  209                 pmd_t *pmd, *pmd_k;
  210                 pte_t *pte_k;
  211 
  212                 pgd = (pgd_t *) pgd_current + offset;
  213                 pgd_k = init_mm.pgd + offset;
  214 
  215                 if (!pgd_present(*pgd_k))
  216                         goto no_context;
  217                 set_pgd(pgd, *pgd_k);
  218 
  219                 pud = pud_offset(pgd, address);
  220                 pud_k = pud_offset(pgd_k, address);
  221                 if (!pud_present(*pud_k))
  222                         goto no_context;
  223 
  224                 pmd = pmd_offset(pud, address);
  225                 pmd_k = pmd_offset(pud_k, address);
  226                 if (!pmd_present(*pmd_k))
  227                         goto no_context;
  228                 set_pmd(pmd, *pmd_k);
  229 
  230                 pte_k = pte_offset_kernel(pmd_k, address);
  231                 if (!pte_present(*pte_k))
  232                         goto no_context;
  233                 return;
  234         }
  235 }

Cache object: 63c73735af2a65f9c237937447a05ce0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.