fault.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:6k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * This file is subject to the terms and conditions of the GNU General Public
  3.  * License.  See the file "COPYING" in the main directory of this archive
  4.  * for more details.
  5.  *
  6.  * Copyright (C) 1995 - 2000 by Ralf Baechle
  7.  * Copyright (C) 1999, 2000 by Silicon Graphics, Inc.
  8.  */
  9. #include <linux/config.h>
  10. #include <linux/signal.h>
  11. #include <linux/sched.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/kernel.h>
  14. #include <linux/errno.h>
  15. #include <linux/string.h>
  16. #include <linux/types.h>
  17. #include <linux/ptrace.h>
  18. #include <linux/mman.h>
  19. #include <linux/mm.h>
  20. #include <linux/smp.h>
  21. #include <linux/smp_lock.h>
  22. #include <linux/version.h>
  23. #include <asm/hardirq.h>
  24. #include <asm/pgalloc.h>
  25. #include <asm/mmu_context.h>
  26. #include <asm/softirq.h>
  27. #include <asm/system.h>
  28. #include <asm/uaccess.h>
  29. #include <asm/ptrace.h>
  30. #define development_version (LINUX_VERSION_CODE & 0x100)
  31. extern void die(char *, struct pt_regs *, unsigned long write);
  32. /*
  33.  * Macro for exception fixup code to access integer registers.
  34.  */
  35. #define dpf_reg(r) (regs->regs[r])
  36. asmlinkage void
  37. dodebug(abi64_no_regargs, struct pt_regs regs)
  38. {
  39. printk("Got syscall %ld, cpu %d proc %s:%d epc 0x%lxn", regs.regs[2],
  40.        smp_processor_id(), current->comm, current->pid, regs.cp0_epc);
  41. }
  42. asmlinkage void
  43. dodebug2(abi64_no_regargs, struct pt_regs regs)
  44. {
  45. unsigned long retaddr;
  46. __asm__ __volatile__(
  47. ".set noreordernt"
  48. "add %0,$0,$31nt"
  49. ".set reorder"
  50. : "=r" (retaddr));
  51. printk("Got exception 0x%lx at 0x%lxn", retaddr, regs.cp0_epc);
  52. }
  53. extern spinlock_t timerlist_lock;
  54. /*
  55.  * Unlock any spinlocks which will prevent us from getting the
  56.  * message out (timerlist_lock is acquired through the
  57.  * console unblank code)
  58.  */
  59. void bust_spinlocks(int yes)
  60. {
  61. spin_lock_init(&timerlist_lock);
  62. if (yes) {
  63. oops_in_progress = 1;
  64. } else {
  65. int loglevel_save = console_loglevel;
  66. #ifdef CONFIG_VT
  67. unblank_screen();
  68. #endif
  69. oops_in_progress = 0;
  70. /*
  71.  * OK, the message is on the console.  Now we call printk()
  72.  * without oops_in_progress set so that printk will give klogd
  73.  * a poke.  Hold onto your hats...
  74.  */
  75. console_loglevel = 15; /* NMI oopser may have shut the console up */
  76. printk(" ");
  77. console_loglevel = loglevel_save;
  78. }
  79. }
  80. /*
  81.  * This routine handles page faults.  It determines the address,
  82.  * and the problem, and then passes it off to one of the appropriate
  83.  * routines.
  84.  */
  85. asmlinkage void
  86. do_page_fault(struct pt_regs *regs, unsigned long write, unsigned long address)
  87. {
  88. struct vm_area_struct * vma;
  89. struct task_struct *tsk = current;
  90. struct mm_struct *mm = tsk->mm;
  91. unsigned long fixup;
  92. siginfo_t info;
  93. /*
  94.  * We fault-in kernel-space virtual memory on-demand. The
  95.  * 'reference' page table is init_mm.pgd.
  96.  *
  97.  * NOTE! We MUST NOT take any locks for this case. We may
  98.  * be in an interrupt or a critical region, and should
  99.  * only copy the information from the master page table,
  100.  * nothing more.
  101.  */
  102. if (address >= TASK_SIZE)
  103. goto vmalloc_fault;
  104. info.si_code = SEGV_MAPERR;
  105. /*
  106.  * If we're in an interrupt or have no user
  107.  * context, we must not take the fault..
  108.  */
  109. if (in_interrupt() || mm == &init_mm)
  110. goto no_context;
  111. #if DEBUG_MIPS64
  112. printk("Cpu%d[%s:%d:%08lx:%ld:%08lx]n", smp_processor_id(), current->comm,
  113. current->pid, address, write, regs->cp0_epc);
  114. #endif
  115. down_read(&mm->mmap_sem);
  116. vma = find_vma(mm, address);
  117. if (!vma)
  118. goto bad_area;
  119. if (vma->vm_start <= address)
  120. goto good_area;
  121. if (!(vma->vm_flags & VM_GROWSDOWN))
  122. goto bad_area;
  123. if (expand_stack(vma, address))
  124. goto bad_area;
  125. /*
  126.  * Ok, we have a good vm_area for this memory access, so
  127.  * we can handle it..
  128.  */
  129. good_area:
  130. info.si_code = SEGV_ACCERR;
  131. if (write) {
  132. if (!(vma->vm_flags & VM_WRITE))
  133. goto bad_area;
  134. } else {
  135. if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
  136. goto bad_area;
  137. }
  138. /*
  139.  * If for any reason at all we couldn't handle the fault,
  140.  * make sure we exit gracefully rather than endlessly redo
  141.  * the fault.
  142.  */
  143. switch (handle_mm_fault(mm, vma, address, write)) {
  144. case 1:
  145. tsk->min_flt++;
  146. break;
  147. case 2:
  148. tsk->maj_flt++;
  149. break;
  150. case 0:
  151. goto do_sigbus;
  152. default:
  153. goto out_of_memory;
  154. }
  155. up_read(&mm->mmap_sem);
  156. return;
  157. /*
  158.  * Something tried to access memory that isn't in our memory map..
  159.  * Fix it, but check if it's kernel or user first..
  160.  */
  161. bad_area:
  162. up_read(&mm->mmap_sem);
  163. bad_area_nosemaphore:
  164. if (user_mode(regs)) {
  165. tsk->thread.cp0_badvaddr = address;
  166. tsk->thread.error_code = write;
  167. #if 0
  168. printk("do_page_fault() #2: sending SIGSEGV to %s for illegal %sn"
  169.        "%08lx (epc == %08lx, ra == %08lx)n",
  170.        tsk->comm,
  171.        write ? "write access to" : "read access from",
  172.        address,
  173.        (unsigned long) regs->cp0_epc,
  174.        (unsigned long) regs->regs[31]);
  175. #endif
  176. info.si_signo = SIGSEGV;
  177. info.si_errno = 0;
  178. /* info.si_code has been set above */
  179. info.si_addr = (void *) address;
  180. force_sig_info(SIGSEGV, &info, tsk);
  181. return;
  182. }
  183. no_context:
  184. /* Are we prepared to handle this kernel fault?  */
  185. fixup = search_exception_table(regs->cp0_epc);
  186. if (fixup) {
  187. long new_epc;
  188. tsk->thread.cp0_baduaddr = address;
  189. new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
  190. if (development_version)
  191. printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)n",
  192.        tsk->comm, regs->cp0_epc, new_epc);
  193. regs->cp0_epc = new_epc;
  194. return;
  195. }
  196. /*
  197.  * Oops. The kernel tried to access some bad page. We'll have to
  198.  * terminate things with extreme prejudice.
  199.  */
  200. bust_spinlocks(1);
  201. printk(KERN_ALERT "Cpu %d Unable to handle kernel paging request at "
  202.        "address %08lx, epc == %08x, ra == %08xn",
  203.        smp_processor_id(), address, (unsigned int) regs->cp0_epc,
  204.                (unsigned int) regs->regs[31]);
  205. die("Oops", regs, write);
  206. do_exit(SIGKILL);
  207. bust_spinlocks(0);
  208. /*
  209.  * We ran out of memory, or some other thing happened to us that made
  210.  * us unable to handle the page fault gracefully.
  211.  */
  212. out_of_memory:
  213. up_read(&mm->mmap_sem);
  214. printk("VM: killing process %sn", tsk->comm);
  215. if (user_mode(regs))
  216. do_exit(SIGKILL);
  217. goto no_context;
  218. do_sigbus:
  219. up_read(&mm->mmap_sem);
  220. /*
  221.  * Send a sigbus, regardless of whether we were in kernel
  222.  * or user mode.
  223.  */
  224. tsk->thread.cp0_badvaddr = address;
  225. info.si_code = SIGBUS;
  226. info.si_errno = 0;
  227. info.si_code = BUS_ADRERR;
  228. info.si_addr = (void *) address;
  229. force_sig_info(SIGBUS, &info, tsk);
  230. /* Kernel mode? Handle exceptions or die */
  231. if (!user_mode(regs))
  232. goto no_context;
  233. return;
  234. vmalloc_fault:
  235. panic("Pagefault for kernel virtual memory");
  236. }