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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/arm/mm/fault-armv.c
  3.  *
  4.  *  Copyright (C) 1995  Linus Torvalds
  5.  *  Modifications for ARM processor (c) 1995-2001 Russell King
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 2 as
  9.  * published by the Free Software Foundation.
  10.  */
  11. #include <linux/config.h>
  12. #include <linux/signal.h>
  13. #include <linux/sched.h>
  14. #include <linux/kernel.h>
  15. #include <linux/errno.h>
  16. #include <linux/string.h>
  17. #include <linux/types.h>
  18. #include <linux/ptrace.h>
  19. #include <linux/mman.h>
  20. #include <linux/mm.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/proc_fs.h>
  23. #include <linux/bitops.h>
  24. #include <linux/init.h>
  25. #include <asm/system.h>
  26. #include <asm/uaccess.h>
  27. #include <asm/pgalloc.h>
  28. #include <asm/pgtable.h>
  29. extern void die_if_kernel(const char *str, struct pt_regs *regs, int err);
  30. extern void show_pte(struct mm_struct *mm, unsigned long addr);
  31. extern int do_page_fault(unsigned long addr, int error_code,
  32.  struct pt_regs *regs);
  33. extern int do_translation_fault(unsigned long addr, int error_code,
  34. struct pt_regs *regs);
  35. extern void do_bad_area(struct task_struct *tsk, struct mm_struct *mm,
  36. unsigned long addr, int error_code,
  37. struct pt_regs *regs);
  38. #ifdef CONFIG_ALIGNMENT_TRAP
  39. extern int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs);
  40. #else
  41. #define do_alignment do_bad
  42. #endif
  43. /*
  44.  * Some section permission faults need to be handled gracefully.
  45.  * They can happen due to a __{get,put}_user during an oops.
  46.  */
  47. static int
  48. do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs)
  49. {
  50. struct task_struct *tsk = current;
  51. do_bad_area(tsk, tsk->active_mm, addr, error_code, regs);
  52. return 0;
  53. }
  54. /*
  55.  * Hook for things that need to trap external faults.  Note that
  56.  * we don't guarantee that this will be the final version of the
  57.  * interface.
  58.  */
  59. int (*external_fault)(unsigned long addr, struct pt_regs *regs);
  60. static int
  61. do_external_fault(unsigned long addr, int error_code, struct pt_regs *regs)
  62. {
  63. if (external_fault)
  64. return external_fault(addr, regs);
  65. return 1;
  66. }
  67. /*
  68.  * This abort handler always returns "fault".
  69.  */
  70. static int
  71. do_bad(unsigned long addr, int error_code, struct pt_regs *regs)
  72. {
  73. return 1;
  74. }
  75. static const struct fsr_info {
  76. int (*fn)(unsigned long addr, int error_code, struct pt_regs *regs);
  77. int sig;
  78. const char *name;
  79. } fsr_info[] = {
  80. { do_bad, SIGSEGV, "vector exception"    },
  81. { do_alignment, SIGILL,  "alignment exception"    },
  82. { do_bad, SIGKILL, "terminal exception"    },
  83. { do_alignment, SIGILL,  "alignment exception"    },
  84. { do_external_fault, SIGBUS,  "external abort on linefetch"    },
  85. { do_translation_fault, SIGSEGV, "section translation fault"    },
  86. { do_external_fault, SIGBUS,  "external abort on linefetch"    },
  87. { do_page_fault, SIGSEGV, "page translation fault"    },
  88. { do_external_fault, SIGBUS,  "external abort on non-linefetch" },
  89. { do_bad, SIGSEGV, "section domain fault"    },
  90. { do_external_fault, SIGBUS,  "external abort on non-linefetch" },
  91. { do_bad, SIGSEGV, "page domain fault"    },
  92. { do_bad, SIGBUS,  "external abort on translation"   },
  93. { do_sect_fault, SIGSEGV, "section permission fault"    },
  94. { do_bad, SIGBUS,  "external abort on translation"   },
  95. { do_page_fault, SIGSEGV, "page permission fault"    }
  96. };
  97. /*
  98.  * Dispatch a data abort to the relevant handler.
  99.  */
  100. asmlinkage void
  101. do_DataAbort(unsigned long addr, int error_code, struct pt_regs *regs, int fsr)
  102. {
  103. const struct fsr_info *inf = fsr_info + (fsr & 15);
  104. if (!inf->fn(addr, error_code, regs))
  105. return;
  106. printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lxn",
  107. inf->name, fsr, addr);
  108. force_sig(inf->sig, current);
  109. show_pte(current->mm, addr);
  110. die_if_kernel("Oops", regs, 0);
  111. }
  112. asmlinkage void
  113. do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
  114. {
  115. do_translation_fault(addr, 0, regs);
  116. }
  117. /*
  118.  * We take the easy way out of this problem - we make the
  119.  * PTE uncacheable.  However, we leave the write buffer on.
  120.  */
  121. static void adjust_pte(struct vm_area_struct *vma, unsigned long address)
  122. {
  123. pgd_t *pgd;
  124. pmd_t *pmd;
  125. pte_t *pte, entry;
  126. pgd = pgd_offset(vma->vm_mm, address);
  127. if (pgd_none(*pgd))
  128. return;
  129. if (pgd_bad(*pgd))
  130. goto bad_pgd;
  131. pmd = pmd_offset(pgd, address);
  132. if (pmd_none(*pmd))
  133. return;
  134. if (pmd_bad(*pmd))
  135. goto bad_pmd;
  136. pte = pte_offset(pmd, address);
  137. entry = *pte;
  138. /*
  139.  * If this page isn't present, or is already setup to
  140.  * fault (ie, is old), we can safely ignore any issues.
  141.  */
  142. if (pte_present(entry) && pte_val(entry) & L_PTE_CACHEABLE) {
  143. flush_cache_page(vma, address);
  144. pte_val(entry) &= ~L_PTE_CACHEABLE;
  145. set_pte(pte, entry);
  146. flush_tlb_page(vma, address);
  147. }
  148. return;
  149. bad_pgd:
  150. pgd_ERROR(*pgd);
  151. pgd_clear(pgd);
  152. return;
  153. bad_pmd:
  154. pmd_ERROR(*pmd);
  155. pmd_clear(pmd);
  156. return;
  157. }
  158. static void
  159. make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page)
  160. {
  161. struct vm_area_struct *mpnt;
  162. struct mm_struct *mm = vma->vm_mm;
  163. unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
  164. int aliases = 0;
  165. /*
  166.  * If we have any shared mappings that are in the same mm
  167.  * space, then we need to handle them specially to maintain
  168.  * cache coherency.
  169.  */
  170. for (mpnt = page->mapping->i_mmap_shared; mpnt;
  171.      mpnt = mpnt->vm_next_share) {
  172. unsigned long off;
  173. /*
  174.  * If this VMA is not in our MM, we can ignore it.
  175.  * Note that we intentionally don't mask out the VMA
  176.  * that we are fixing up.
  177.  */
  178. if (mpnt->vm_mm != mm || mpnt == vma)
  179. continue;
  180. /*
  181.  * If the page isn't in this VMA, we can also ignore it.
  182.  */
  183. if (pgoff < mpnt->vm_pgoff)
  184. continue;
  185. off = pgoff - mpnt->vm_pgoff;
  186. if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)
  187. continue;
  188. /*
  189.  * Ok, it is within mpnt.  Fix it up.
  190.  */
  191. adjust_pte(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
  192. aliases ++;
  193. }
  194. if (aliases)
  195. adjust_pte(vma, addr);
  196. }
  197. /*
  198.  * Take care of architecture specific things when placing a new PTE into
  199.  * a page table, or changing an existing PTE.  Basically, there are two
  200.  * things that we need to take care of:
  201.  *
  202.  *  1. If PG_dcache_dirty is set for the page, we need to ensure
  203.  *     that any cache entries for the kernels virtual memory
  204.  *     range are written back to the page.
  205.  *  2. If we have multiple shared mappings of the same space in
  206.  *     an object, we need to deal with the cache aliasing issues.
  207.  *
  208.  * Note that the page_table_lock will be held.
  209.  */
  210. void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
  211. {
  212. struct page *page = pte_page(pte);
  213. if (VALID_PAGE(page) && page->mapping) {
  214. if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) {
  215. unsigned long kvirt = (unsigned long)page_address(page);
  216. cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0);
  217. }
  218. make_coherent(vma, addr, page);
  219. }
  220. }