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

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: fault.c,v 1.49 2001/10/06 19:46:00 lethal Exp $
  2.  *
  3.  *  linux/arch/sh/mm/fault.c
  4.  *  Copyright (C) 1999  Niibe Yutaka
  5.  *
  6.  *  Based on linux/arch/i386/mm/fault.c:
  7.  *   Copyright (C) 1995  Linus Torvalds
  8.  */
  9. #include <linux/signal.h>
  10. #include <linux/sched.h>
  11. #include <linux/kernel.h>
  12. #include <linux/errno.h>
  13. #include <linux/string.h>
  14. #include <linux/types.h>
  15. #include <linux/ptrace.h>
  16. #include <linux/mman.h>
  17. #include <linux/mm.h>
  18. #include <linux/smp.h>
  19. #include <linux/smp_lock.h>
  20. #include <linux/interrupt.h>
  21. #include <asm/system.h>
  22. #include <asm/io.h>
  23. #include <asm/uaccess.h>
  24. #include <asm/pgalloc.h>
  25. #include <asm/hardirq.h>
  26. #include <asm/mmu_context.h>
  27. extern void die(const char *,struct pt_regs *,long);
  28. /*
  29.  * Ugly, ugly, but the goto's result in better assembly..
  30.  */
  31. int __verify_write(const void * addr, unsigned long size)
  32. {
  33. struct vm_area_struct * vma;
  34. unsigned long start = (unsigned long) addr;
  35. if (!size)
  36. return 1;
  37. vma = find_vma(current->mm, start);
  38. if (!vma)
  39. goto bad_area;
  40. if (vma->vm_start > start)
  41. goto check_stack;
  42. good_area:
  43. if (!(vma->vm_flags & VM_WRITE))
  44. goto bad_area;
  45. size--;
  46. size += start & ~PAGE_MASK;
  47. size >>= PAGE_SHIFT;
  48. start &= PAGE_MASK;
  49. for (;;) {
  50. if (handle_mm_fault(current->mm, vma, start, 1) <= 0)
  51. goto bad_area;
  52. if (!size)
  53. break;
  54. size--;
  55. start += PAGE_SIZE;
  56. if (start < vma->vm_end)
  57. continue;
  58. vma = vma->vm_next;
  59. if (!vma || vma->vm_start != start)
  60. goto bad_area;
  61. if (!(vma->vm_flags & VM_WRITE))
  62. goto bad_area;;
  63. }
  64. return 1;
  65. check_stack:
  66. if (!(vma->vm_flags & VM_GROWSDOWN))
  67. goto bad_area;
  68. if (expand_stack(vma, start) == 0)
  69. goto good_area;
  70. bad_area:
  71. return 0;
  72. }
  73. /*
  74.  * This routine handles page faults.  It determines the address,
  75.  * and the problem, and then passes it off to one of the appropriate
  76.  * routines.
  77.  */
  78. asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
  79.       unsigned long address)
  80. {
  81. struct task_struct *tsk;
  82. struct mm_struct *mm;
  83. struct vm_area_struct * vma;
  84. unsigned long page;
  85. unsigned long fixup;
  86. tsk = current;
  87. mm = tsk->mm;
  88. /*
  89.  * If we're in an interrupt or have no user
  90.  * context, we must not take the fault..
  91.  */
  92. if (in_interrupt() || !mm)
  93. goto no_context;
  94. down_read(&mm->mmap_sem);
  95. vma = find_vma(mm, address);
  96. if (!vma)
  97. goto bad_area;
  98. if (vma->vm_start <= address)
  99. goto good_area;
  100. if (!(vma->vm_flags & VM_GROWSDOWN))
  101. goto bad_area;
  102. if (expand_stack(vma, address))
  103. goto bad_area;
  104. /*
  105.  * Ok, we have a good vm_area for this memory access, so
  106.  * we can handle it..
  107.  */
  108. good_area:
  109. if (writeaccess) {
  110. if (!(vma->vm_flags & VM_WRITE))
  111. goto bad_area;
  112. } else {
  113. if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
  114. goto bad_area;
  115. }
  116. /*
  117.  * If for any reason at all we couldn't handle the fault,
  118.  * make sure we exit gracefully rather than endlessly redo
  119.  * the fault.
  120.  */
  121. survive:
  122. switch (handle_mm_fault(mm, vma, address, writeaccess)) {
  123. case 1:
  124. tsk->min_flt++;
  125. break;
  126. case 2:
  127. tsk->maj_flt++;
  128. break;
  129. case 0:
  130. goto do_sigbus;
  131. default:
  132. goto out_of_memory;
  133. }
  134. up_read(&mm->mmap_sem);
  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. tsk->thread.address = address;
  144. tsk->thread.error_code = writeaccess;
  145. force_sig(SIGSEGV, tsk);
  146. return;
  147. }
  148. no_context:
  149. /* Are we prepared to handle this kernel fault?  */
  150. fixup = search_exception_table(regs->pc);
  151. if (fixup != 0) {
  152. regs->pc = fixup;
  153. return;
  154. }
  155. /*
  156.  * Oops. The kernel tried to access some bad page. We'll have to
  157.  * terminate things with extreme prejudice.
  158.  *
  159.  */
  160. if (address < PAGE_SIZE)
  161. printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
  162. else
  163. printk(KERN_ALERT "Unable to handle kernel paging request");
  164. printk(" at virtual address %08lxn", address);
  165. printk(KERN_ALERT "pc = %08lxn", regs->pc);
  166. asm volatile("mov.l %1, %0"
  167.      : "=r" (page)
  168.      : "m" (__m(MMU_TTB)));
  169. if (page) {
  170. page = ((unsigned long *) page)[address >> 22];
  171. printk(KERN_ALERT "*pde = %08lxn", page);
  172. if (page & _PAGE_PRESENT) {
  173. page &= PAGE_MASK;
  174. address &= 0x003ff000;
  175. page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
  176. printk(KERN_ALERT "*pte = %08lxn", page);
  177. }
  178. }
  179. die("Oops", regs, writeaccess);
  180. do_exit(SIGKILL);
  181. /*
  182.  * We ran out of memory, or some other thing happened to us that made
  183.  * us unable to handle the page fault gracefully.
  184.  */
  185. out_of_memory:
  186. up_read(&mm->mmap_sem);
  187. if (current->pid == 1) {
  188. current->policy |= SCHED_YIELD;
  189. schedule();
  190. down_read(&mm->mmap_sem);
  191. goto survive;
  192. }
  193. printk("VM: killing process %sn", tsk->comm);
  194. if (user_mode(regs))
  195. do_exit(SIGKILL);
  196. goto no_context;
  197. do_sigbus:
  198. up_read(&mm->mmap_sem);
  199. /*
  200.  * Send a sigbus, regardless of whether we were in kernel
  201.  * or user mode.
  202.  */
  203. tsk->thread.address = address;
  204. tsk->thread.error_code = writeaccess;
  205. tsk->thread.trap_no = 14;
  206. force_sig(SIGBUS, tsk);
  207. /* Kernel mode? Handle exceptions or die */
  208. if (!user_mode(regs))
  209. goto no_context;
  210. }
  211. /*
  212.  * Called with interrupt disabled.
  213.  */
  214. asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
  215.        unsigned long address)
  216. {
  217. pgd_t *dir;
  218. pmd_t *pmd;
  219. pte_t *pte;
  220. pte_t entry;
  221. if (address >= P3SEG && address < P4SEG)
  222. dir = pgd_offset_k(address);
  223. else if (address >= TASK_SIZE)
  224. return 1;
  225. else
  226. dir = pgd_offset(current->mm, address);
  227. pmd = pmd_offset(dir, address);
  228. if (pmd_none(*pmd))
  229. return 1;
  230. if (pmd_bad(*pmd)) {
  231. pmd_ERROR(*pmd);
  232. pmd_clear(pmd);
  233. return 1;
  234. }
  235. pte = pte_offset(pmd, address);
  236. entry = *pte;
  237. if (pte_none(entry) || pte_not_present(entry)
  238.     || (writeaccess && !pte_write(entry)))
  239. return 1;
  240. if (writeaccess)
  241. entry = pte_mkdirty(entry);
  242. entry = pte_mkyoung(entry);
  243. #if defined(__SH4__)
  244. /*
  245.  * ITLB is not affected by "ldtlb" instruction.
  246.  * So, we need to flush the entry by ourselves.
  247.  */
  248. __flush_tlb_page(get_asid(), address&PAGE_MASK);
  249. #endif
  250. set_pte(pte, entry);
  251. update_mmu_cache(NULL, address, entry);
  252. return 0;
  253. }
  254. void update_mmu_cache(struct vm_area_struct * vma,
  255.       unsigned long address, pte_t pte)
  256. {
  257. unsigned long flags;
  258. unsigned long pteval;
  259. unsigned long vpn;
  260. #if defined(__SH4__)
  261. struct page *page;
  262. unsigned long ptea;
  263. #endif
  264. /* Ptrace may call this routine. */
  265. if (vma && current->active_mm != vma->vm_mm)
  266. return;
  267. #if defined(__SH4__)
  268. page = pte_page(pte);
  269. if (VALID_PAGE(page) && !test_bit(PG_mapped, &page->flags)) {
  270. unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
  271. __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE);
  272. __set_bit(PG_mapped, &page->flags);
  273. }
  274. #endif
  275. save_and_cli(flags);
  276. /* Set PTEH register */
  277. vpn = (address & MMU_VPN_MASK) | get_asid();
  278. ctrl_outl(vpn, MMU_PTEH);
  279. pteval = pte_val(pte);
  280. #if defined(__SH4__)
  281. /* Set PTEA register */
  282. /* TODO: make this look less hacky */
  283. ptea = ((pteval >> 28) & 0xe) | (pteval & 0x1);
  284. ctrl_outl(ptea, MMU_PTEA);
  285. #endif
  286. /* Set PTEL register */
  287. pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
  288. /* conveniently, we want all the software flags to be 0 anyway */
  289. ctrl_outl(pteval, MMU_PTEL);
  290. /* Load the TLB */
  291. asm volatile("ldtlb": /* no output */ : /* no input */ : "memory");
  292. restore_flags(flags);
  293. }
  294. void __flush_tlb_page(unsigned long asid, unsigned long page)
  295. {
  296. unsigned long addr, data;
  297. /*
  298.  * NOTE: PTEH.ASID should be set to this MM
  299.  *       _AND_ we need to write ASID to the array.
  300.  *
  301.  * It would be simple if we didn't need to set PTEH.ASID...
  302.  */
  303. #if defined(__sh3__)
  304. addr = MMU_TLB_ADDRESS_ARRAY |(page & 0x1F000)| MMU_PAGE_ASSOC_BIT;
  305. data = (page & 0xfffe0000) | asid; /* VALID bit is off */
  306. ctrl_outl(data, addr);
  307. #elif defined(__SH4__)
  308. addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
  309. data = page | asid; /* VALID bit is off */
  310. jump_to_P2();
  311. ctrl_outl(data, addr);
  312. back_to_P1();
  313. #endif
  314. }
  315. void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
  316. {
  317. if (vma->vm_mm && vma->vm_mm->context != NO_CONTEXT) {
  318. unsigned long flags;
  319. unsigned long asid;
  320. unsigned long saved_asid = MMU_NO_ASID;
  321. asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK;
  322. page &= PAGE_MASK;
  323. save_and_cli(flags);
  324. if (vma->vm_mm != current->mm) {
  325. saved_asid = get_asid();
  326. set_asid(asid);
  327. }
  328. __flush_tlb_page(asid, page);
  329. if (saved_asid != MMU_NO_ASID)
  330. set_asid(saved_asid);
  331. restore_flags(flags);
  332. }
  333. }
  334. void flush_tlb_range(struct mm_struct *mm, unsigned long start,
  335.      unsigned long end)
  336. {
  337. if (mm->context != NO_CONTEXT) {
  338. unsigned long flags;
  339. int size;
  340. save_and_cli(flags);
  341. size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  342. if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
  343. mm->context = NO_CONTEXT;
  344. if (mm == current->mm)
  345. activate_context(mm);
  346. } else {
  347. unsigned long asid = mm->context&MMU_CONTEXT_ASID_MASK;
  348. unsigned long saved_asid = MMU_NO_ASID;
  349. start &= PAGE_MASK;
  350. end += (PAGE_SIZE - 1);
  351. end &= PAGE_MASK;
  352. if (mm != current->mm) {
  353. saved_asid = get_asid();
  354. set_asid(asid);
  355. }
  356. while (start < end) {
  357. __flush_tlb_page(asid, start);
  358. start += PAGE_SIZE;
  359. }
  360. if (saved_asid != MMU_NO_ASID)
  361. set_asid(saved_asid);
  362. }
  363. restore_flags(flags);
  364. }
  365. }
  366. void flush_tlb_mm(struct mm_struct *mm)
  367. {
  368. /* Invalidate all TLB of this process. */
  369. /* Instead of invalidating each TLB, we get new MMU context. */
  370. if (mm->context != NO_CONTEXT) {
  371. unsigned long flags;
  372. save_and_cli(flags);
  373. mm->context = NO_CONTEXT;
  374. if (mm == current->mm)
  375. activate_context(mm);
  376. restore_flags(flags);
  377. }
  378. }
  379. void flush_tlb_all(void)
  380. {
  381. unsigned long flags, status;
  382. /*
  383.  * Flush all the TLB.
  384.  *
  385.  * Write to the MMU control register's bit:
  386.  *  TF-bit for SH-3, TI-bit for SH-4.
  387.  *      It's same position, bit #2.
  388.  */
  389. save_and_cli(flags);
  390. status = ctrl_inl(MMUCR);
  391. status |= 0x04;
  392. ctrl_outl(status, MMUCR);
  393. restore_flags(flags);
  394. }