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

嵌入式Linux

开发平台:

Unix_Linux

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