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

Linux/Unix编程

开发平台:

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