linux 核心處理缺頁異常函數:do_page_fault ,2.4.0版

來源:互聯網
上載者:User
部落格已遷移至:http://kulv.sinaapp.com/,這裡不再使用

關於核心地址空間如何和進程地址空間合在一起,下面函數能看出來。

/*<br /> * This routine handles page faults. It determines the address,<br /> * and the problem, and then passes it off to one of the appropriate<br /> * routines.<br /> *<br /> * error_code:<br /> *bit 0 == 0 means no page found, 1 means protection fault<br /> *bit 1 == 0 means read, 1 means write<br /> *bit 2 == 0 means kernel, 1 means user-mode<br /> */<br />asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)<br />{<br />struct task_struct *tsk;<br />struct mm_struct *mm;<br />struct vm_area_struct * vma;<br />unsigned long address;<br />unsigned long page;<br />unsigned long fixup;<br />int write;<br />siginfo_t info;</p><p>/* get the address */<br />__asm__("movl %%cr2,%0":"=r" (address));</p><p>tsk = current;</p><p>/*<br /> * We fault-in kernel-space virtual memory on-demand. The<br /> * 'reference' page table is init_mm.pgd.<br /> *<br /> * NOTE! We MUST NOT take any locks for this case. We may<br /> * be in an interrupt or a critical region, and should<br /> * only copy the information from the master page table,<br /> * nothing more.<br /> */<br />if (address >= TASK_SIZE)//關鍵地方就在這分叉了,如果是核心地址空間3G以上,那麼···你懂的。<br />goto vmalloc_fault;</p><p>mm = tsk->mm;<br />info.si_code = SEGV_MAPERR;<br />/*<br /> * If we're in an interrupt or have no user<br /> * context, we must not take the fault..<br /> */<br />if (in_interrupt() || !mm)<br />goto no_context;<br />down(&mm->mmap_sem);<br />vma = find_vma(mm, address);<br />if (!vma)<br />goto bad_area;<br />if (vma->vm_start <= address)<br />goto good_area;<br />if (!(vma->vm_flags & VM_GROWSDOWN))<br />goto bad_area;<br />if (error_code & 4) {<br />/*<br /> * accessing the stack below %esp is always a bug.<br /> * The "+ 32" is there due to some instructions (like<br /> * pusha) doing post-decrement on the stack and that<br /> * doesn't show up until later..<br /> */<br />if (address + 32 < regs->esp)<br />goto bad_area;<br />}<br />if (expand_stack(vma, address))<br />goto bad_area;<br />/*<br /> * Ok, we have a good vm_area for this memory access, so<br /> * we can handle it..<br /> */<br />good_area:<br />info.si_code = SEGV_ACCERR;<br />write = 0;<br />switch (error_code & 3) {<br />default:/* 3: write, present */<br />#ifdef TEST_VERIFY_AREA<br />if (regs->cs == KERNEL_CS)<br />printk("WP fault at %08lx/n", regs->eip);<br />#endif<br />/* fall through */<br />case 2:/* write, not present */<br />if (!(vma->vm_flags & VM_WRITE))<br />goto bad_area;<br />write++;<br />break;<br />case 1:/* read, present */<br />goto bad_area;<br />case 0:/* read, not present */<br />if (!(vma->vm_flags & (VM_READ | VM_EXEC)))<br />goto bad_area;<br />}</p><p>/*<br /> * If for any reason at all we couldn't handle the fault,<br /> * make sure we exit gracefully rather than endlessly redo<br /> * the fault.<br /> */<br />switch (handle_mm_fault(mm, vma, address, write)) {<br />case 1:<br />tsk->min_flt++;<br />break;<br />case 2:<br />tsk->maj_flt++;<br />break;<br />case 0:<br />goto do_sigbus;<br />default:<br />goto out_of_memory;<br />}</p><p>/*<br /> * Did it hit the DOS screen memory VA from vm86 mode?<br /> */<br />if (regs->eflags & VM_MASK) {<br />unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;<br />if (bit < 32)<br />tsk->thread.screen_bitmap |= 1 << bit;<br />}<br />up(&mm->mmap_sem);<br />return;</p><p>/*<br /> * Something tried to access memory that isn't in our memory map..<br /> * Fix it, but check if it's kernel or user first..<br /> */<br />bad_area:<br />up(&mm->mmap_sem);</p><p>bad_area_nosemaphore:<br />/* User mode accesses just cause a SIGSEGV */<br />if (error_code & 4) {<br />tsk->thread.cr2 = address;<br />tsk->thread.error_code = error_code;<br />tsk->thread.trap_no = 14;<br />info.si_signo = SIGSEGV;<br />info.si_errno = 0;<br />/* info.si_code has been set above */<br />info.si_addr = (void *)address;<br />force_sig_info(SIGSEGV, &info, tsk);<br />return;<br />}</p><p>/*<br /> * Pentium F0 0F C7 C8 bug workaround.<br /> */<br />if (boot_cpu_data.f00f_bug) {<br />unsigned long nr;</p><p>nr = (address - idt) >> 3;</p><p>if (nr == 6) {<br />do_invalid_op(regs, 0);<br />return;<br />}<br />}</p><p>no_context:<br />/* Are we prepared to handle this kernel fault? */<br />if ((fixup = search_exception_table(regs->eip)) != 0) {<br />regs->eip = fixup;<br />return;<br />}</p><p>/*<br /> * Oops. The kernel tried to access some bad page. We'll have to<br /> * terminate things with extreme prejudice.<br /> */</p><p>bust_spinlocks();</p><p>if (address < PAGE_SIZE)<br />printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");<br />else<br />printk(KERN_ALERT "Unable to handle kernel paging request");<br />printk(" at virtual address %08lx/n",address);<br />printk(" printing eip:/n");<br />printk("%08lx/n", regs->eip);<br />asm("movl %%cr3,%0":"=r" (page));<br />page = ((unsigned long *) __va(page))[address >> 22];<br />printk(KERN_ALERT "*pde = %08lx/n", page);<br />if (page & 1) {<br />page &= PAGE_MASK;<br />address &= 0x003ff000;<br />page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];<br />printk(KERN_ALERT "*pte = %08lx/n", page);<br />}<br />die("Oops", regs, error_code);<br />do_exit(SIGKILL);</p><p>/*<br /> * We ran out of memory, or some other thing happened to us that made<br /> * us unable to handle the page fault gracefully.<br /> */<br />out_of_memory:<br />up(&mm->mmap_sem);<br />printk("VM: killing process %s/n", tsk->comm);<br />if (error_code & 4)<br />do_exit(SIGKILL);<br />goto no_context;</p><p>do_sigbus:<br />up(&mm->mmap_sem);</p><p>/*<br /> * Send a sigbus, regardless of whether we were in kernel<br /> * or user mode.<br /> */<br />tsk->thread.cr2 = address;<br />tsk->thread.error_code = error_code;<br />tsk->thread.trap_no = 14;<br />info.si_code = SIGBUS;<br />info.si_errno = 0;<br />info.si_code = BUS_ADRERR;<br />info.si_addr = (void *)address;<br />force_sig_info(SIGBUS, &info, tsk);</p><p>/* Kernel mode? Handle exceptions or die */<br />if (!(error_code & 4))<br />goto no_context;<br />return;</p><p>vmalloc_fault://下面就是如何處理核心地址空間的問題了。這裡實現核心全域頁目錄表和進程頁目錄表同步<br />{<br />/*<br /> * Synchronize this task's top level page-table<br /> * with the 'reference' page table.<br /> */<br />int offset = __pgd_offset(address);<br />pgd_t *pgd, *pgd_k;<br />pmd_t *pmd, *pmd_k;<br />pgd = tsk->active_mm->pgd + offset;<br />pgd_k = init_mm.pgd + offset;<br />if (!pgd_present(*pgd)) {<br />if (!pgd_present(*pgd_k))<br />goto bad_area_nosemaphore;<br />set_pgd(pgd, *pgd_k);<br />return;<br />}<br />pmd = pmd_offset(pgd, address);<br />pmd_k = pmd_offset(pgd_k, address);<br />if (pmd_present(*pmd) || !pmd_present(*pmd_k))<br />goto bad_area_nosemaphore;<br />set_pmd(pmd, *pmd_k);<br />return;<br />}<br />}<br />  

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.