fault.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  arch/ppc/mm/fault.c
  3.  *
  4.  *  PowerPC version 
  5.  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  6.  *
  7.  *  Derived from "arch/i386/mm/fault.c"
  8.  *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  9.  *
  10.  *  Modified by Cort Dougan and Paul Mackerras.
  11.  *
  12.  *  Modified for PPC64 by Dave Engebretsen (engebret@ibm.com)
  13.  *
  14.  *  This program is free software; you can redistribute it and/or
  15.  *  modify it under the terms of the GNU General Public License
  16.  *  as published by the Free Software Foundation; either version
  17.  *  2 of the License, or (at your option) any later version.
  18.  */
  19. #include <linux/config.h>
  20. #include <linux/signal.h>
  21. #include <linux/sched.h>
  22. #include <linux/kernel.h>
  23. #include <linux/errno.h>
  24. #include <linux/string.h>
  25. #include <linux/types.h>
  26. #include <linux/ptrace.h>
  27. #include <linux/mman.h>
  28. #include <linux/mm.h>
  29. #include <linux/interrupt.h>
  30. #include <asm/page.h>
  31. #include <asm/pgtable.h>
  32. #include <asm/mmu.h>
  33. #include <asm/mmu_context.h>
  34. #include <asm/system.h>
  35. #include <asm/uaccess.h>
  36. #include <asm/ppcdebug.h>
  37. #if defined(CONFIG_KDB)
  38. #include <linux/kdb.h>
  39. #endif
  40. #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) || defined(CONFIG_KDB)
  41. extern void (*debugger)(struct pt_regs *);
  42. extern void (*debugger_fault_handler)(struct pt_regs *);
  43. extern int (*debugger_dabr_match)(struct pt_regs *);
  44. int debugger_kernel_faults = 1;
  45. #endif
  46. extern void die_if_kernel(char *, struct pt_regs *, long);
  47. void bad_page_fault(struct pt_regs *, unsigned long);
  48. void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
  49. #ifdef CONFIG_PPCDBG
  50. extern unsigned long get_srr0(void);
  51. extern unsigned long get_srr1(void);
  52. #endif
  53. /*
  54.  * For 600- and 800-family processors, the error_code parameter is DSISR
  55.  * for a data fault, SRR1 for an instruction fault.
  56.  */
  57. void do_page_fault(struct pt_regs *regs, unsigned long address,
  58.    unsigned long error_code)
  59. {
  60. struct vm_area_struct * vma;
  61. struct mm_struct *mm = current->mm;
  62. siginfo_t info;
  63. unsigned long code = SEGV_MAPERR;
  64. unsigned long is_write = error_code & 0x02000000;
  65. unsigned long mm_fault_return;
  66. PPCDBG(PPCDBG_MM, "Entering do_page_fault: addr = 0x%16.16lx, error_code = %lxntregs_trap = %lx, srr0 = %lx, srr1 = %lxn", address, error_code, regs->trap, get_srr0(), get_srr1());
  67. /*
  68.  * Fortunately the bit assignments in SRR1 for an instruction
  69.  * fault and DSISR for a data fault are mostly the same for the
  70.  * bits we are interested in.  But there are some bits which
  71.  * indicate errors in DSISR but can validly be set in SRR1.
  72.  */
  73. if (regs->trap == 0x400)
  74. error_code &= 0x48200000;
  75. #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
  76. if (debugger_fault_handler && (regs->trap == 0x300 ||
  77. regs->trap == 0x380)) {
  78. debugger_fault_handler(regs);
  79. return;
  80. }
  81. if (error_code & 0x00400000) {
  82. /* DABR match */
  83. if (debugger_dabr_match(regs))
  84. return;
  85. }
  86. #endif /* CONFIG_XMON || CONFIG_KGDB */
  87. if (in_interrupt() || mm == NULL) {
  88. bad_page_fault(regs, address);
  89. return;
  90. }
  91. down_read(&mm->mmap_sem);
  92. vma = find_vma(mm, address);
  93. PPCDBG(PPCDBG_MM, "tdo_page_fault: vma = 0x%16.16lxn", vma);
  94. if (!vma) {
  95.         PPCDBG(PPCDBG_MM, "tdo_page_fault: !vman");
  96. goto bad_area;
  97. }
  98. PPCDBG(PPCDBG_MM, "tdo_page_fault: vma->vm_start = 0x%16.16lx, vma->vm_flags = 0x%16.16lxn", vma->vm_start, vma->vm_flags);
  99. if (vma->vm_start <= address) {
  100. goto good_area;
  101. }
  102. if (!(vma->vm_flags & VM_GROWSDOWN)) {
  103. PPCDBG(PPCDBG_MM, "tdo_page_fault: vma->vm_flags = %lx, %lxn", vma->vm_flags, VM_GROWSDOWN);
  104. goto bad_area;
  105. }
  106. if (expand_stack(vma, address)) {
  107. PPCDBG(PPCDBG_MM, "tdo_page_fault: expand_stackn");
  108. goto bad_area;
  109. }
  110. good_area:
  111. code = SEGV_ACCERR;
  112. /* a write */
  113. if (is_write) {
  114. if (!(vma->vm_flags & VM_WRITE))
  115. goto bad_area;
  116. /* a read */
  117. } else {
  118. /* protection fault */
  119. if (error_code & 0x08000000)
  120. goto bad_area;
  121. if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
  122. goto bad_area;
  123. }
  124. /*
  125.  * If for any reason at all we couldn't handle the fault,
  126.  * make sure we exit gracefully rather than endlessly redo
  127.  * the fault.
  128.  */
  129. PPCDBG(PPCDBG_MM, "tdo_page_fault: calling handle_mm_faultn");
  130.         mm_fault_return = handle_mm_fault(mm, vma, address, is_write);
  131. PPCDBG(PPCDBG_MM, "tdo_page_fault: handle_mm_fault = 0x%lxn", 
  132.        mm_fault_return);
  133.         switch(mm_fault_return) {
  134.         case 1:
  135.                 current->min_flt++;
  136.                 break;
  137.         case 2:
  138.                 current->maj_flt++;
  139.                 break;
  140.         case 0:
  141.                 goto do_sigbus;
  142.         default:
  143.                 goto out_of_memory;
  144. }
  145. up_read(&mm->mmap_sem);
  146. return;
  147. bad_area:
  148. up_read(&mm->mmap_sem);
  149. /* User mode accesses cause a SIGSEGV */
  150. if (user_mode(regs)) {
  151. info.si_signo = SIGSEGV;
  152. info.si_errno = 0;
  153. info.si_code = code;
  154. info.si_addr = (void *) address;
  155. PPCDBG(PPCDBG_SIGNAL, "Bad addr in user: 0x%lxn", address);
  156. #ifdef CONFIG_XMON
  157.         ifppcdebug(PPCDBG_SIGNALXMON)
  158.              PPCDBG_ENTER_DEBUGGER_REGS(regs);
  159. #endif
  160. force_sig_info(SIGSEGV, &info, current);
  161. return;
  162. }
  163. bad_page_fault(regs, address);
  164. return;
  165. /*
  166.  * We ran out of memory, or some other thing happened to us that made
  167.  * us unable to handle the page fault gracefully.
  168.  */
  169. out_of_memory:
  170. up_read(&mm->mmap_sem);
  171. printk("VM: killing process %sn", current->comm);
  172. if (user_mode(regs))
  173. do_exit(SIGKILL);
  174. bad_page_fault(regs, address);
  175. return;
  176. do_sigbus:
  177. up_read(&mm->mmap_sem);
  178. info.si_signo = SIGBUS;
  179. info.si_errno = 0;
  180. info.si_code = BUS_ADRERR;
  181. info.si_addr = (void *)address;
  182. force_sig_info (SIGBUS, &info, current);
  183. if (!user_mode(regs))
  184. bad_page_fault(regs, address);
  185. }
  186. /*
  187.  * bad_page_fault is called when we have a bad access from the kernel.
  188.  * It is called from do_page_fault above and from some of the procedures
  189.  * in traps.c.
  190.  */
  191. void
  192. bad_page_fault(struct pt_regs *regs, unsigned long address)
  193. {
  194. unsigned long fixup;
  195. /* Are we prepared to handle this fault?  */
  196. if ((fixup = search_exception_table(regs->nip)) != 0) {
  197. regs->nip = fixup;
  198. return;
  199. }
  200. /* kernel has accessed a bad area */
  201. show_regs(regs);
  202. #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
  203. if (debugger_kernel_faults)
  204. debugger(regs);
  205. #endif
  206. #if defined(CONFIG_KDB)
  207. kdb(KDB_REASON_FAULT, regs->trap, regs);
  208. #endif
  209. print_backtrace( (unsigned long *)regs->gpr[1] );
  210. panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d",
  211.       regs->nip,regs->link,address,current->comm,current->pid);
  212. }