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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/alpha/mm/fault.c
  3.  *
  4.  *  Copyright (C) 1995  Linus Torvalds
  5.  */
  6. #include <linux/config.h>
  7. #include <linux/sched.h>
  8. #include <linux/kernel.h>
  9. #include <linux/mm.h>
  10. #include <asm/io.h>
  11. #define __EXTERN_INLINE inline
  12. #include <asm/mmu_context.h>
  13. #include <asm/pgalloc.h>
  14. #undef  __EXTERN_INLINE
  15. #include <linux/signal.h>
  16. #include <linux/errno.h>
  17. #include <linux/string.h>
  18. #include <linux/types.h>
  19. #include <linux/ptrace.h>
  20. #include <linux/mman.h>
  21. #include <linux/smp.h>
  22. #include <linux/smp_lock.h>
  23. #include <linux/interrupt.h>
  24. #include <asm/system.h>
  25. #include <asm/uaccess.h>
  26. extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *);
  27. /*
  28.  * Force a new ASN for a task.
  29.  */
  30. #ifndef CONFIG_SMP
  31. unsigned long last_asn = ASN_FIRST_VERSION;
  32. #endif
  33. extern void
  34. __load_new_mm_context(struct mm_struct *next_mm)
  35. {
  36. unsigned long mmc;
  37. mmc = __get_new_mm_context(next_mm, smp_processor_id());
  38. next_mm->context[smp_processor_id()] = mmc;
  39. current->thread.asn = mmc & HARDWARE_ASN_MASK;
  40.         current->thread.ptbr
  41.   = ((unsigned long) next_mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
  42. __reload_thread(&current->thread);
  43. }
  44. /*
  45.  * This routine handles page faults.  It determines the address,
  46.  * and the problem, and then passes it off to handle_mm_fault().
  47.  *
  48.  * mmcsr:
  49.  * 0 = translation not valid
  50.  * 1 = access violation
  51.  * 2 = fault-on-read
  52.  * 3 = fault-on-execute
  53.  * 4 = fault-on-write
  54.  *
  55.  * cause:
  56.  * -1 = instruction fetch
  57.  * 0 = load
  58.  * 1 = store
  59.  *
  60.  * Registers $9 through $15 are saved in a block just prior to `regs' and
  61.  * are saved and restored around the call to allow exception code to
  62.  * modify them.
  63.  */
  64. /* Macro for exception fixup code to access integer registers.  */
  65. #define dpf_reg(r)
  66. (((unsigned long *)regs)[(r) <= 8 ? (r) : (r) <= 15 ? (r)-16 :
  67.  (r) <= 18 ? (r)+8 : (r)-10])
  68. asmlinkage void
  69. do_page_fault(unsigned long address, unsigned long mmcsr,
  70.       long cause, struct pt_regs *regs)
  71. {
  72. struct vm_area_struct * vma;
  73. struct mm_struct *mm = current->mm;
  74. unsigned int fixup;
  75. int fault;
  76. /* As of EV6, a load into $31/$f31 is a prefetch, and never faults
  77.    (or is suppressed by the PALcode).  Support that for older CPUs
  78.    by ignoring such an instruction.  */
  79. if (cause == 0) {
  80. unsigned int insn;
  81. __get_user(insn, (unsigned int *)regs->pc);
  82. if ((insn >> 21 & 0x1f) == 0x1f &&
  83.     /* ldq ldl ldt lds ldg ldf ldwu ldbu */
  84.     (1ul << (insn >> 26) & 0x30f00001400ul)) {
  85. regs->pc += 4;
  86. return;
  87. }
  88. }
  89. /* If we're in an interrupt context, or have no user context,
  90.    we must not take the fault.  */
  91. if (!mm || in_interrupt())
  92. goto no_context;
  93. #ifdef CONFIG_ALPHA_LARGE_VMALLOC
  94. if (address >= TASK_SIZE)
  95. goto vmalloc_fault;
  96. #endif
  97. down_read(&mm->mmap_sem);
  98. vma = find_vma(mm, address);
  99. if (!vma)
  100. goto bad_area;
  101. if (vma->vm_start <= address)
  102. goto good_area;
  103. if (!(vma->vm_flags & VM_GROWSDOWN))
  104. goto bad_area;
  105. if (expand_stack(vma, address))
  106. goto bad_area;
  107. /*
  108.  * Ok, we have a good vm_area for this memory access, so
  109.  * we can handle it..
  110.  */
  111. good_area:
  112. if (cause < 0) {
  113. if (!(vma->vm_flags & VM_EXEC))
  114. goto bad_area;
  115. } else if (!cause) {
  116. /* Allow reads even for write-only mappings */
  117. if (!(vma->vm_flags & (VM_READ | VM_WRITE)))
  118. goto bad_area;
  119. } else {
  120. if (!(vma->vm_flags & VM_WRITE))
  121. goto bad_area;
  122. }
  123.  survive:
  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. fault = handle_mm_fault(mm, vma, address, cause > 0);
  130. up_read(&mm->mmap_sem);
  131. if (fault < 0)
  132. goto out_of_memory;
  133. if (fault == 0)
  134. goto do_sigbus;
  135. return;
  136. /*
  137.  * Something tried to access memory that isn't in our memory map..
  138.  * Fix it, but check if it's kernel or user first..
  139.  */
  140. bad_area:
  141. up_read(&mm->mmap_sem);
  142. if (user_mode(regs)) {
  143. force_sig(SIGSEGV, current);
  144. return;
  145. }
  146. no_context:
  147. /* Are we prepared to handle this fault as an exception?  */
  148. if ((fixup = search_exception_table(regs->pc, regs->gp)) != 0) {
  149. unsigned long newpc;
  150. newpc = fixup_exception(dpf_reg, fixup, regs->pc);
  151. #if 0
  152. printk("%s: Exception at [<%lx>] (%lx) handled successfullyn",
  153.        current->comm, regs->pc, newpc);
  154. #endif
  155. regs->pc = newpc;
  156. return;
  157. }
  158. /*
  159.  * Oops. The kernel tried to access some bad page. We'll have to
  160.  * terminate things with extreme prejudice.
  161.  */
  162. printk(KERN_ALERT "Unable to handle kernel paging request at "
  163.        "virtual address %016lxn", address);
  164. die_if_kernel("Oops", regs, cause, (unsigned long*)regs - 16);
  165. do_exit(SIGKILL);
  166. /*
  167.  * We ran out of memory, or some other thing happened to us that made
  168.  * us unable to handle the page fault gracefully.
  169.  */
  170. out_of_memory:
  171. if (current->pid == 1) {
  172. current->policy |= SCHED_YIELD;
  173. schedule();
  174. down_read(&mm->mmap_sem);
  175. goto survive;
  176. }
  177. printk(KERN_ALERT "VM: killing process %s(%d)n",
  178.        current->comm, current->pid);
  179. if (!user_mode(regs))
  180. goto no_context;
  181. do_exit(SIGKILL);
  182. do_sigbus:
  183. /*
  184.  * Send a sigbus, regardless of whether we were in kernel
  185.  * or user mode.
  186.  */
  187. force_sig(SIGBUS, current);
  188. if (!user_mode(regs))
  189. goto no_context;
  190. return;
  191. #ifdef CONFIG_ALPHA_LARGE_VMALLOC
  192. vmalloc_fault:
  193. if (user_mode(regs)) {
  194. force_sig(SIGSEGV, current);
  195. return;
  196. } else {
  197. /* Synchronize this task's top level page-table
  198.    with the "reference" page table from init.  */
  199. long offset = __pgd_offset(address);
  200. pgd_t *pgd, *pgd_k;
  201. pgd = current->active_mm->pgd + offset;
  202. pgd_k = swapper_pg_dir + offset;
  203. if (!pgd_present(*pgd) && pgd_present(*pgd_k)) {
  204. pgd_val(*pgd) = pgd_val(*pgd_k);
  205. return;
  206. }
  207. goto no_context;
  208. }
  209. #endif
  210. }