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

Linux/Unix编程

开发平台:

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. if (current->pid == 1) {
  187. yield();
  188. goto survive;
  189. }
  190. up_read(&mm->mmap_sem);
  191. printk("VM: killing process %sn", tsk->comm);
  192. if (user_mode(regs))
  193. do_exit(SIGKILL);
  194. goto no_context;
  195. do_sigbus:
  196. up_read(&mm->mmap_sem);
  197. /*
  198.  * Send a sigbus, regardless of whether we were in kernel
  199.  * or user mode.
  200.  */
  201. tsk->thread.address = address;
  202. tsk->thread.error_code = writeaccess;
  203. tsk->thread.trap_no = 14;
  204. force_sig(SIGBUS, tsk);
  205. /* Kernel mode? Handle exceptions or die */
  206. if (!user_mode(regs))
  207. goto no_context;
  208. }
  209. /*
  210.  * Called with interrupt disabled.
  211.  */
  212. asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
  213.        unsigned long address)
  214. {
  215. pgd_t *dir;
  216. pmd_t *pmd;
  217. pte_t *pte;
  218. pte_t entry;
  219. if (address >= P3SEG && address < P4SEG)
  220. dir = pgd_offset_k(address);
  221. else if (address >= TASK_SIZE)
  222. return 1;
  223. else
  224. dir = pgd_offset(current->mm, address);
  225. pmd = pmd_offset(dir, address);
  226. if (pmd_none(*pmd))
  227. return 1;
  228. if (pmd_bad(*pmd)) {
  229. pmd_ERROR(*pmd);
  230. pmd_clear(pmd);
  231. return 1;
  232. }
  233. pte = pte_offset(pmd, address);
  234. entry = *pte;
  235. if (pte_none(entry) || pte_not_present(entry)
  236.     || (writeaccess && !pte_write(entry)))
  237. return 1;
  238. if (writeaccess)
  239. entry = pte_mkdirty(entry);
  240. entry = pte_mkyoung(entry);
  241. #if defined(__SH4__)
  242. /*
  243.  * ITLB is not affected by "ldtlb" instruction.
  244.  * So, we need to flush the entry by ourselves.
  245.  */
  246. __flush_tlb_page(get_asid(), address&PAGE_MASK);
  247. #endif
  248. set_pte(pte, entry);
  249. update_mmu_cache(NULL, address, entry);
  250. return 0;
  251. }
  252. void update_mmu_cache(struct vm_area_struct * vma,
  253.       unsigned long address, pte_t pte)
  254. {
  255. unsigned long flags;
  256. unsigned long pteval;
  257. unsigned long vpn;
  258. #if defined(__SH4__)
  259. struct page *page;
  260. unsigned long ptea;
  261. #endif
  262. /* Ptrace may call this routine. */
  263. if (vma && current->active_mm != vma->vm_mm)
  264. return;
  265. #if defined(__SH4__)
  266. page = pte_page(pte);
  267. if (VALID_PAGE(page) && !test_bit(PG_mapped, &page->flags)) {
  268. unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
  269. __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE);
  270. __set_bit(PG_mapped, &page->flags);
  271. }
  272. #endif
  273. save_and_cli(flags);
  274. /* Set PTEH register */
  275. vpn = (address & MMU_VPN_MASK) | get_asid();
  276. ctrl_outl(vpn, MMU_PTEH);
  277. pteval = pte_val(pte);
  278. #if defined(__SH4__)
  279. /* Set PTEA register */
  280. /* TODO: make this look less hacky */
  281. ptea = ((pteval >> 28) & 0xe) | (pteval & 0x1);
  282. ctrl_outl(ptea, MMU_PTEA);
  283. #endif
  284. /* Set PTEL register */
  285. pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
  286. /* conveniently, we want all the software flags to be 0 anyway */
  287. ctrl_outl(pteval, MMU_PTEL);
  288. /* Load the TLB */
  289. asm volatile("ldtlb": /* no output */ : /* no input */ : "memory");
  290. restore_flags(flags);
  291. }
  292. void __flush_tlb_page(unsigned long asid, unsigned long page)
  293. {
  294. unsigned long addr, data;
  295. /*
  296.  * NOTE: PTEH.ASID should be set to this MM
  297.  *       _AND_ we need to write ASID to the array.
  298.  *
  299.  * It would be simple if we didn't need to set PTEH.ASID...
  300.  */
  301. #if defined(__sh3__)
  302. addr = MMU_TLB_ADDRESS_ARRAY |(page & 0x1F000)| MMU_PAGE_ASSOC_BIT;
  303. data = (page & 0xfffe0000) | asid; /* VALID bit is off */
  304. ctrl_outl(data, addr);
  305. #elif defined(__SH4__)
  306. addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
  307. data = page | asid; /* VALID bit is off */
  308. jump_to_P2();
  309. ctrl_outl(data, addr);
  310. back_to_P1();
  311. #endif
  312. }
  313. void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
  314. {
  315. if (vma->vm_mm && vma->vm_mm->context != NO_CONTEXT) {
  316. unsigned long flags;
  317. unsigned long asid;
  318. unsigned long saved_asid = MMU_NO_ASID;
  319. asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK;
  320. page &= PAGE_MASK;
  321. save_and_cli(flags);
  322. if (vma->vm_mm != current->mm) {
  323. saved_asid = get_asid();
  324. set_asid(asid);
  325. }
  326. __flush_tlb_page(asid, page);
  327. if (saved_asid != MMU_NO_ASID)
  328. set_asid(saved_asid);
  329. restore_flags(flags);
  330. }
  331. }
  332. void flush_tlb_range(struct mm_struct *mm, unsigned long start,
  333.      unsigned long end)
  334. {
  335. if (mm->context != NO_CONTEXT) {
  336. unsigned long flags;
  337. int size;
  338. save_and_cli(flags);
  339. size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  340. if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
  341. mm->context = NO_CONTEXT;
  342. if (mm == current->mm)
  343. activate_context(mm);
  344. } else {
  345. unsigned long asid = mm->context&MMU_CONTEXT_ASID_MASK;
  346. unsigned long saved_asid = MMU_NO_ASID;
  347. start &= PAGE_MASK;
  348. end += (PAGE_SIZE - 1);
  349. end &= PAGE_MASK;
  350. if (mm != current->mm) {
  351. saved_asid = get_asid();
  352. set_asid(asid);
  353. }
  354. while (start < end) {
  355. __flush_tlb_page(asid, start);
  356. start += PAGE_SIZE;
  357. }
  358. if (saved_asid != MMU_NO_ASID)
  359. set_asid(saved_asid);
  360. }
  361. restore_flags(flags);
  362. }
  363. }
  364. void flush_tlb_mm(struct mm_struct *mm)
  365. {
  366. /* Invalidate all TLB of this process. */
  367. /* Instead of invalidating each TLB, we get new MMU context. */
  368. if (mm->context != NO_CONTEXT) {
  369. unsigned long flags;
  370. save_and_cli(flags);
  371. mm->context = NO_CONTEXT;
  372. if (mm == current->mm)
  373. activate_context(mm);
  374. restore_flags(flags);
  375. }
  376. }
  377. void flush_tlb_all(void)
  378. {
  379. unsigned long flags, status;
  380. /*
  381.  * Flush all the TLB.
  382.  *
  383.  * Write to the MMU control register's bit:
  384.  *  TF-bit for SH-3, TI-bit for SH-4.
  385.  *      It's same position, bit #2.
  386.  */
  387. save_and_cli(flags);
  388. status = ctrl_inl(MMUCR);
  389. status |= 0x04;
  390. ctrl_outl(status, MMUCR);
  391. restore_flags(flags);
  392. }