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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/i386/mm/fault.c
  3.  *
  4.  *  Copyright (C) 1995  Linus Torvalds
  5.  */
  6. #include <linux/signal.h>
  7. #include <linux/sched.h>
  8. #include <linux/kernel.h>
  9. #include <linux/errno.h>
  10. #include <linux/string.h>
  11. #include <linux/types.h>
  12. #include <linux/ptrace.h>
  13. #include <linux/mman.h>
  14. #include <linux/mm.h>
  15. #include <linux/smp.h>
  16. #include <linux/smp_lock.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/init.h>
  19. #include <linux/tty.h>
  20. #include <linux/vt_kern.h> /* For unblank_screen() */
  21. #include <asm/system.h>
  22. #include <asm/uaccess.h>
  23. #include <asm/pgalloc.h>
  24. #include <asm/hardirq.h>
  25. extern void die(const char *,struct pt_regs *,long);
  26. /*
  27.  * Ugly, ugly, but the goto's result in better assembly..
  28.  */
  29. int __verify_write(const void * addr, unsigned long size)
  30. {
  31. struct vm_area_struct * vma;
  32. unsigned long start = (unsigned long) addr;
  33. if (!size)
  34. return 1;
  35. vma = find_vma(current->mm, start);
  36. if (!vma)
  37. goto bad_area;
  38. if (vma->vm_start > start)
  39. goto check_stack;
  40. good_area:
  41. if (!(vma->vm_flags & VM_WRITE))
  42. goto bad_area;
  43. size--;
  44. size += start & ~PAGE_MASK;
  45. size >>= PAGE_SHIFT;
  46. start &= PAGE_MASK;
  47. for (;;) {
  48. survive:
  49. {
  50. int fault = handle_mm_fault(current->mm, vma, start, 1);
  51. if (!fault)
  52. goto bad_area;
  53. if (fault < 0)
  54. goto out_of_memory;
  55. }
  56. if (!size)
  57. break;
  58. size--;
  59. start += PAGE_SIZE;
  60. if (start < vma->vm_end)
  61. continue;
  62. vma = vma->vm_next;
  63. if (!vma || vma->vm_start != start)
  64. goto bad_area;
  65. if (!(vma->vm_flags & VM_WRITE))
  66. goto bad_area;;
  67. }
  68. return 1;
  69. check_stack:
  70. if (!(vma->vm_flags & VM_GROWSDOWN))
  71. goto bad_area;
  72. if (expand_stack(vma, start) == 0)
  73. goto good_area;
  74. bad_area:
  75. return 0;
  76. out_of_memory:
  77. if (current->pid == 1) {
  78. yield();
  79. goto survive;
  80. }
  81. goto bad_area;
  82. }
  83. extern spinlock_t timerlist_lock;
  84. /*
  85.  * Unlock any spinlocks which will prevent us from getting the
  86.  * message out (timerlist_lock is acquired through the
  87.  * console unblank code)
  88.  */
  89. void bust_spinlocks(int yes)
  90. {
  91. spin_lock_init(&timerlist_lock);
  92. if (yes) {
  93. oops_in_progress = 1;
  94. #ifdef CONFIG_SMP
  95. global_irq_lock = 0; /* Many serial drivers do __global_cli() */
  96. #endif
  97. } else {
  98. int loglevel_save = console_loglevel;
  99. #ifdef CONFIG_VT
  100. unblank_screen();
  101. #endif
  102. oops_in_progress = 0;
  103. /*
  104.  * OK, the message is on the console.  Now we call printk()
  105.  * without oops_in_progress set so that printk will give klogd
  106.  * a poke.  Hold onto your hats...
  107.  */
  108. console_loglevel = 15; /* NMI oopser may have shut the console up */
  109. printk(" ");
  110. console_loglevel = loglevel_save;
  111. }
  112. }
  113. asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
  114. extern unsigned long idt;
  115. /*
  116.  * This routine handles page faults.  It determines the address,
  117.  * and the problem, and then passes it off to one of the appropriate
  118.  * routines.
  119.  *
  120.  * error_code:
  121.  * bit 0 == 0 means no page found, 1 means protection fault
  122.  * bit 1 == 0 means read, 1 means write
  123.  * bit 2 == 0 means kernel, 1 means user-mode
  124.  */
  125. asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
  126. {
  127. struct task_struct *tsk;
  128. struct mm_struct *mm;
  129. struct vm_area_struct * vma;
  130. unsigned long address;
  131. unsigned long page;
  132. unsigned long fixup;
  133. int write;
  134. siginfo_t info;
  135. /* get the address */
  136. __asm__("movl %%cr2,%0":"=r" (address));
  137. /* It's safe to allow irq's after cr2 has been saved */
  138. if (regs->eflags & X86_EFLAGS_IF)
  139. local_irq_enable();
  140. tsk = current;
  141. /*
  142.  * We fault-in kernel-space virtual memory on-demand. The
  143.  * 'reference' page table is init_mm.pgd.
  144.  *
  145.  * NOTE! We MUST NOT take any locks for this case. We may
  146.  * be in an interrupt or a critical region, and should
  147.  * only copy the information from the master page table,
  148.  * nothing more.
  149.  *
  150.  * This verifies that the fault happens in kernel space
  151.  * (error_code & 4) == 0, and that the fault was not a
  152.  * protection error (error_code & 1) == 0.
  153.  */
  154. if (address >= TASK_SIZE && !(error_code & 5))
  155. goto vmalloc_fault;
  156. mm = tsk->mm;
  157. info.si_code = SEGV_MAPERR;
  158. /*
  159.  * If we're in an interrupt or have no user
  160.  * context, we must not take the fault..
  161.  */
  162. if (in_interrupt() || !mm)
  163. goto no_context;
  164. down_read(&mm->mmap_sem);
  165. vma = find_vma(mm, address);
  166. if (!vma)
  167. goto bad_area;
  168. if (vma->vm_start <= address)
  169. goto good_area;
  170. if (!(vma->vm_flags & VM_GROWSDOWN))
  171. goto bad_area;
  172. if (error_code & 4) {
  173. /*
  174.  * accessing the stack below %esp is always a bug.
  175.  * The "+ 32" is there due to some instructions (like
  176.  * pusha) doing post-decrement on the stack and that
  177.  * doesn't show up until later..
  178.  */
  179. if (address + 32 < regs->esp)
  180. goto bad_area;
  181. }
  182. if (expand_stack(vma, address))
  183. goto bad_area;
  184. /*
  185.  * Ok, we have a good vm_area for this memory access, so
  186.  * we can handle it..
  187.  */
  188. good_area:
  189. info.si_code = SEGV_ACCERR;
  190. write = 0;
  191. switch (error_code & 3) {
  192. default: /* 3: write, present */
  193. #ifdef TEST_VERIFY_AREA
  194. if (regs->cs == KERNEL_CS)
  195. printk("WP fault at %08lxn", regs->eip);
  196. #endif
  197. /* fall through */
  198. case 2: /* write, not present */
  199. if (!(vma->vm_flags & VM_WRITE))
  200. goto bad_area;
  201. write++;
  202. break;
  203. case 1: /* read, present */
  204. goto bad_area;
  205. case 0: /* read, not present */
  206. if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
  207. goto bad_area;
  208. }
  209.  survive:
  210. /*
  211.  * If for any reason at all we couldn't handle the fault,
  212.  * make sure we exit gracefully rather than endlessly redo
  213.  * the fault.
  214.  */
  215. switch (handle_mm_fault(mm, vma, address, write)) {
  216. case 1:
  217. tsk->min_flt++;
  218. break;
  219. case 2:
  220. tsk->maj_flt++;
  221. break;
  222. case 0:
  223. goto do_sigbus;
  224. default:
  225. goto out_of_memory;
  226. }
  227. /*
  228.  * Did it hit the DOS screen memory VA from vm86 mode?
  229.  */
  230. if (regs->eflags & VM_MASK) {
  231. unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
  232. if (bit < 32)
  233. tsk->thread.screen_bitmap |= 1 << bit;
  234. }
  235. up_read(&mm->mmap_sem);
  236. return;
  237. /*
  238.  * Something tried to access memory that isn't in our memory map..
  239.  * Fix it, but check if it's kernel or user first..
  240.  */
  241. bad_area:
  242. up_read(&mm->mmap_sem);
  243. /* User mode accesses just cause a SIGSEGV */
  244. if (error_code & 4) {
  245. tsk->thread.cr2 = address;
  246. tsk->thread.error_code = error_code;
  247. tsk->thread.trap_no = 14;
  248. info.si_signo = SIGSEGV;
  249. info.si_errno = 0;
  250. /* info.si_code has been set above */
  251. info.si_addr = (void *)address;
  252. force_sig_info(SIGSEGV, &info, tsk);
  253. return;
  254. }
  255. /*
  256.  * Pentium F0 0F C7 C8 bug workaround.
  257.  */
  258. if (boot_cpu_data.f00f_bug) {
  259. unsigned long nr;
  260. nr = (address - idt) >> 3;
  261. if (nr == 6) {
  262. do_invalid_op(regs, 0);
  263. return;
  264. }
  265. }
  266. no_context:
  267. /* Are we prepared to handle this kernel fault?  */
  268. if ((fixup = search_exception_table(regs->eip)) != 0) {
  269. regs->eip = fixup;
  270. return;
  271. }
  272. /*
  273.  * Oops. The kernel tried to access some bad page. We'll have to
  274.  * terminate things with extreme prejudice.
  275.  */
  276. bust_spinlocks(1);
  277. if (address < PAGE_SIZE)
  278. printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
  279. else
  280. printk(KERN_ALERT "Unable to handle kernel paging request");
  281. printk(" at virtual address %08lxn",address);
  282. printk(" printing eip:n");
  283. printk("%08lxn", regs->eip);
  284. asm("movl %%cr3,%0":"=r" (page));
  285. page = ((unsigned long *) __va(page))[address >> 22];
  286. printk(KERN_ALERT "*pde = %08lxn", page);
  287. if (page & 1) {
  288. page &= PAGE_MASK;
  289. address &= 0x003ff000;
  290. page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
  291. printk(KERN_ALERT "*pte = %08lxn", page);
  292. }
  293. die("Oops", regs, error_code);
  294. bust_spinlocks(0);
  295. do_exit(SIGKILL);
  296. /*
  297.  * We ran out of memory, or some other thing happened to us that made
  298.  * us unable to handle the page fault gracefully.
  299.  */
  300. out_of_memory:
  301. if (tsk->pid == 1) {
  302. yield();
  303. goto survive;
  304. }
  305. up_read(&mm->mmap_sem);
  306. printk("VM: killing process %sn", tsk->comm);
  307. if (error_code & 4)
  308. do_exit(SIGKILL);
  309. goto no_context;
  310. do_sigbus:
  311. up_read(&mm->mmap_sem);
  312. /*
  313.  * Send a sigbus, regardless of whether we were in kernel
  314.  * or user mode.
  315.  */
  316. tsk->thread.cr2 = address;
  317. tsk->thread.error_code = error_code;
  318. tsk->thread.trap_no = 14;
  319. info.si_signo = SIGBUS;
  320. info.si_errno = 0;
  321. info.si_code = BUS_ADRERR;
  322. info.si_addr = (void *)address;
  323. force_sig_info(SIGBUS, &info, tsk);
  324. /* Kernel mode? Handle exceptions or die */
  325. if (!(error_code & 4))
  326. goto no_context;
  327. return;
  328. vmalloc_fault:
  329. {
  330. /*
  331.  * Synchronize this task's top level page-table
  332.  * with the 'reference' page table.
  333.  *
  334.  * Do _not_ use "tsk" here. We might be inside
  335.  * an interrupt in the middle of a task switch..
  336.  */
  337. int offset = __pgd_offset(address);
  338. pgd_t *pgd, *pgd_k;
  339. pmd_t *pmd, *pmd_k;
  340. pte_t *pte_k;
  341. asm("movl %%cr3,%0":"=r" (pgd));
  342. pgd = offset + (pgd_t *)__va(pgd);
  343. pgd_k = init_mm.pgd + offset;
  344. if (!pgd_present(*pgd_k))
  345. goto no_context;
  346. set_pgd(pgd, *pgd_k);
  347. pmd = pmd_offset(pgd, address);
  348. pmd_k = pmd_offset(pgd_k, address);
  349. if (!pmd_present(*pmd_k))
  350. goto no_context;
  351. set_pmd(pmd, *pmd_k);
  352. pte_k = pte_offset(pmd_k, address);
  353. if (!pte_present(*pte_k))
  354. goto no_context;
  355. return;
  356. }
  357. }