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

Linux/Unix编程

开发平台:

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. siginfo_t info;
  77. /* As of EV6, a load into $31/$f31 is a prefetch, and never faults
  78.    (or is suppressed by the PALcode).  Support that for older CPUs
  79.    by ignoring such an instruction.  */
  80. if (cause == 0) {
  81. unsigned int insn;
  82. __get_user(insn, (unsigned int *)regs->pc);
  83. if ((insn >> 21 & 0x1f) == 0x1f &&
  84.     /* ldq ldl ldt lds ldg ldf ldwu ldbu */
  85.     (1ul << (insn >> 26) & 0x30f00001400ul)) {
  86. regs->pc += 4;
  87. return;
  88. }
  89. }
  90. /* If we're in an interrupt context, or have no user context,
  91.    we must not take the fault.  */
  92. if (!mm || in_interrupt())
  93. goto no_context;
  94. info.si_code = SEGV_MAPERR;
  95. #ifdef CONFIG_ALPHA_LARGE_VMALLOC
  96. if (address >= TASK_SIZE)
  97. goto vmalloc_fault;
  98. #endif
  99. down_read(&mm->mmap_sem);
  100. vma = find_vma(mm, address);
  101. if (!vma)
  102. goto bad_area;
  103. if (vma->vm_start <= address)
  104. goto good_area;
  105. if (!(vma->vm_flags & VM_GROWSDOWN))
  106. goto bad_area;
  107. if (expand_stack(vma, address))
  108. goto bad_area;
  109. /*
  110.  * Ok, we have a good vm_area for this memory access, so
  111.  * we can handle it..
  112.  */
  113. good_area:
  114. info.si_code = SEGV_ACCERR;
  115. if (cause < 0) {
  116. if (!(vma->vm_flags & VM_EXEC))
  117. goto bad_area;
  118. } else if (!cause) {
  119. /* Allow reads even for write-only mappings */
  120. if (!(vma->vm_flags & (VM_READ | VM_WRITE)))
  121. goto bad_area;
  122. } else {
  123. if (!(vma->vm_flags & VM_WRITE))
  124. goto bad_area;
  125. }
  126.  survive:
  127. /*
  128.  * If for any reason at all we couldn't handle the fault,
  129.  * make sure we exit gracefully rather than endlessly redo
  130.  * the fault.
  131.  */
  132. fault = handle_mm_fault(mm, vma, address, cause > 0);
  133. if (fault < 0)
  134. goto out_of_memory;
  135. if (fault == 0)
  136. goto do_sigbus;
  137. up_read(&mm->mmap_sem);
  138. return;
  139. /*
  140.  * Something tried to access memory that isn't in our memory map..
  141.  * Fix it, but check if it's kernel or user first..
  142.  */
  143. bad_area:
  144. up_read(&mm->mmap_sem);
  145. if (user_mode(regs)) {
  146. info.si_signo = SIGSEGV;
  147. info.si_errno = 0;
  148. /* info.si_code has been set above */
  149. info.si_addr = (void *)address;
  150. force_sig_info(SIGSEGV,&info,current);
  151. return;
  152. }
  153. no_context:
  154. /* Are we prepared to handle this fault as an exception?  */
  155. if ((fixup = search_exception_table(regs->pc, regs->gp)) != 0) {
  156. unsigned long newpc;
  157. newpc = fixup_exception(dpf_reg, fixup, regs->pc);
  158. #if 0
  159. printk("%s: Exception at [<%lx>] (%lx) handled successfullyn",
  160.        current->comm, regs->pc, newpc);
  161. #endif
  162. regs->pc = newpc;
  163. return;
  164. }
  165. /*
  166.  * Oops. The kernel tried to access some bad page. We'll have to
  167.  * terminate things with extreme prejudice.
  168.  */
  169. printk(KERN_ALERT "Unable to handle kernel paging request at "
  170.        "virtual address %016lxn", address);
  171. die_if_kernel("Oops", regs, cause, (unsigned long*)regs - 16);
  172. do_exit(SIGKILL);
  173. /*
  174.  * We ran out of memory, or some other thing happened to us that made
  175.  * us unable to handle the page fault gracefully.
  176.  */
  177. out_of_memory:
  178. if (current->pid == 1) {
  179. yield();
  180. goto survive;
  181. }
  182. up_read(&mm->mmap_sem);
  183. printk(KERN_ALERT "VM: killing process %s(%d)n",
  184.        current->comm, current->pid);
  185. if (!user_mode(regs))
  186. goto no_context;
  187. do_exit(SIGKILL);
  188. do_sigbus:
  189. up_read(&mm->mmap_sem);
  190. /*
  191.  * Send a sigbus, regardless of whether we were in kernel
  192.  * or user mode.
  193.  */
  194. info.si_signo = SIGBUS;
  195. info.si_errno = 0;
  196. /* not sure si_code value here  */
  197. info.si_code =  BUS_ADRERR;
  198. info.si_addr = (void *)address;
  199. force_sig_info(SIGBUS,&info,current);
  200. if (!user_mode(regs))
  201. goto no_context;
  202. return;
  203. #ifdef CONFIG_ALPHA_LARGE_VMALLOC
  204. vmalloc_fault:
  205. if (user_mode(regs)) {
  206. info.si_signo = SIGSEGV;
  207. info.si_errno = 0;
  208. /* info.si_code has been set above */
  209. info.si_addr = (void *)address;
  210. force_sig_info(SIGSEGV,&info,current);
  211. return;
  212. } else {
  213. /* Synchronize this task's top level page-table
  214.    with the "reference" page table from init.  */
  215. long offset = __pgd_offset(address);
  216. pgd_t *pgd, *pgd_k;
  217. pgd = current->active_mm->pgd + offset;
  218. pgd_k = swapper_pg_dir + offset;
  219. if (!pgd_present(*pgd) && pgd_present(*pgd_k)) {
  220. pgd_val(*pgd) = pgd_val(*pgd_k);
  221. return;
  222. }
  223. goto no_context;
  224. }
  225. #endif
  226. }