⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 001_arch_i386_mm_fault_.html

📁 重读linux 2.4.2o所写的笔记
💻 HTML
📖 第 1 页 / 共 3 页
字号:
  <html lang="zh-CN" xmlns:gdoc="">  <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <style type="text/css">/* default css */table {  font-size: 1em;  line-height: inherit;}div, address, ol, ul, li, option, select {   margin-top: 0px;  margin-bottom: 0px;}p {  margin: 0px;}body {        margin: 0px;          padding: 0px;    font-family: Verdana, sans-serif;  font-size: 10pt;  background-color: #ffffff;}h6 { font-size: 10pt }h5 { font-size: 11pt }h4 { font-size: 12pt }h3 { font-size: 13pt }h2 { font-size: 14pt }h1 { font-size: 16pt }blockquote {padding: 10px; border: 1px #DDD dashed }a img {border: 0}div.google_header, div.google_footer {  position: relative;  margin-top: 1em;  margin-bottom: 1em;}/* end default css */  /* default print css */    @media print {    body {       padding: 0;       margin: 0;     }    div.google_header, div.google_footer {      display: block;      min-height: 0;      border: none;    }    div.google_header {      flow: static(header);    }    /* used to insert page numbers */    div.google_header::before, div.google_footer::before {      position: absolute;      top: 0;    }    div.google_footer {      flow: static(footer);    }    /* always consider this element at the start of the doc */    div#google_footer {      flow: static(footer, start);    }    span.google_pagenumber {      content: counter(page);    }    span.google_pagecount {      content: counter(pages);    }  }  @page {    @top {      content: flow(header);    }    @bottom {      content: flow(footer);    }  }  /* end default print css */ /* custom css *//* end custom css */  /* ui edited css */    body {    font-family: Verdana;        font-size: 10.0pt;    line-height: normal;    background-color: #ffffff;  }    .documentBG {    background-color: #ffffff;  }  /* end ui edited css */</style>   </head>  <body  revision="dcbsxfpf_42gxpn5gdj:7">      <br>
<div style=TEXT-ALIGN:center>
  <table border=0 cellpadding=3 cellspacing=0 id=qmlk style="TEXT-ALIGN:left; MARGIN-LEFT:auto; MARGIN-RIGHT:auto" width=768>
    <tbody>
    <tr>
      <td width=100%>
        arch/i386/fault.c<br>
        &nbsp;&nbsp;&nbsp;&nbsp; 页面异常, swap, address space, shmem, filemap<br>
        &nbsp;&nbsp;&nbsp; &nbsp;<br>
        <br>
        &nbsp;&nbsp;&nbsp; 从文件开始,而不拘泥于文件。&nbsp; &nbsp;<br>
        &nbsp;&nbsp; &nbsp;<br>
        &nbsp;&nbsp;&nbsp; 此文件内只有两个函数。<br>
        <br>
        1.&nbsp; __verify_write&nbsp; int __verify_write(const void * addr,
        unsigned long size)<br>
        <br>
        &nbsp;&nbsp;&nbsp; 此函数主要应用于检查用户传递的内存块是否"可写". 可写意味着:<br>
        &nbsp;&nbsp;&nbsp; a)内核容许其写,即vma的记录;<br>
        &nbsp;&nbsp;&nbsp; b)相应的物理页面已经分配,即虚存已经有了对应的映射. 主要使用者是<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; access_ok (include/asm-i386/uaccess.h).<br>
        &nbsp; &nbsp;<br>
        &nbsp;&nbsp; access_ok 大量应用于和用户空间进行数据交换的时候检查用户传递的内<br>
        存是否合法.以避免在内核中产生页面访问异常,被别有用心的程序破坏了"大<br>
        好形势".<br>
        <br>
        &nbsp;&nbsp;&nbsp; 下面是此函数,以及注释.<br>
        /*<br>
        &nbsp;* Ugly, ugly, but the goto's result in better assembly..<br>
        &nbsp;* 在操作用户传递的内存时检查其有效性,如果容许则预先扩展其堆栈<br>
        &nbsp;* 或者为虚拟内存分配物理页面<br>
        &nbsp;*/<br>
        int __verify_write(const void * addr, unsigned long size)<br>
        {<br>
        &nbsp;&nbsp; &nbsp;struct vm_area_struct * vma;<br>
        &nbsp;&nbsp; &nbsp;unsigned long start = (unsigned long) addr;<br>
        <br>
        &nbsp;&nbsp; &nbsp;if (!size)<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return 1;<br>
        <br>
        &nbsp;&nbsp; &nbsp;vma = find_vma(current-&gt;mm,
        start);//寻找vma满足start&lt;vma-&gt;end<br>
        &nbsp;&nbsp; &nbsp;if (!vma)<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto bad_area; //访问非法地址<br>
        &nbsp;&nbsp; &nbsp;if (vma-&gt;vm_start &gt; start) //访问堆栈空洞,需要扩展用户堆栈<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto check_stack;<br>
        <br>
        good_area:<br>
        &nbsp;&nbsp; &nbsp;if (!(vma-&gt;vm_flags &amp; VM_WRITE))<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto bad_area;<br>
        &nbsp;&nbsp; &nbsp;size--;<br>
        &nbsp;&nbsp; &nbsp;size += start &amp; ~PAGE_MASK;<br>
        &nbsp;&nbsp; &nbsp;size &gt;&gt;= PAGE_SHIFT;<br>
        &nbsp;&nbsp; &nbsp;start &amp;= PAGE_MASK;<br>
        <br>
        &nbsp;&nbsp; &nbsp;for (;;) {<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
        (handle_mm_fault(current-&gt;mm, vma, start, 1) &lt;= 0)//检查page
        table-&gt;<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto
        bad_area;&nbsp; //page dir-&gt;page本身, 有任何没有分配的页面,即刻分配物理<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
        (!size)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //页面<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;size--;<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;start += PAGE_SIZE;<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (start &lt; vma-&gt;vm_end)<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;continue;<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;vma = vma-&gt;vm_next;<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (!vma || vma-&gt;vm_start !=
        start)<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto bad_area;<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (!(vma-&gt;vm_flags &amp;
        VM_WRITE))<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto bad_area;;<br>
        &nbsp;&nbsp; &nbsp;}<br>
        &nbsp;&nbsp; &nbsp;return 1;<br>
        <br>
        check_stack:<br>
        &nbsp;&nbsp; &nbsp;if (!(vma-&gt;vm_flags &amp; VM_GROWSDOWN))
        //必须是堆栈(或者有VM_GROWSDOWN属性)<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto bad_area;<br>
        &nbsp;&nbsp; &nbsp;if (expand_stack(vma, start) == 0) //只是扩展其vma中的地址范围<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto good_area;&nbsp;
        //还要给扩展的堆栈分配物理页面<br>
        <br>
        bad_area:<br>
        &nbsp;&nbsp; &nbsp;return 0;<br>
        }<br>
        <br>
        &nbsp;&nbsp;&nbsp; 就这个函数本身,其中的注释已经足以理解其逻辑. 需要着重强调的是:<br>
        &nbsp;&nbsp; a) vma<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma是内核管理虚拟内存的手段,其中记录了进程所拥有的虚拟地址的<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 范围和属性,是处理内存异常的依据之一. 如果进程所有的虚存较多,<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma还可以组织成平衡树,以加快查找速度,不过这是vma资源的管理算法,<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而不是内核的逻辑. 逻辑和具体资源管理算法应该区别对待,以免陷入<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 万劫不复的细节中去.所以, find_vma 本身的细节不用去追究,否则分<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 析之粒度就过于详细,反而迷失于内核之中了.<br>
        <br>
        &nbsp;&nbsp; b) handle_mm_fault (mm/memory.c)<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 此函数其使用在这里是"不务正业"的, 使用在本文件的下一个函数<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do_page_fault才是正道.其逻辑是比较简单的. 内核假定有三级页面映<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 射,此函数顺着指定地址摸下去将涉及到的page table entry, page
        dir<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; entry, 逐个检查一遍如有未分配之page dir , page,
        就分配一个并设<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 置好相应的entry.其复杂之处在于<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        handle_mm_fault-&gt;handle_pte_fault(也在memory.c之中):<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 先来注释一把:<br>
        <br>
        /* 此段不翻译了,我们不是在翻译内核源码.<br>
        &nbsp;* These routines also need to handle stuff like marking pages
        dirty<br>
        &nbsp;* and/or accessed for architectures that don't do it in hardware
        (most<br>
        &nbsp;* RISC architectures).&nbsp; The early dirtying is also good on
        the i386.<br>
        &nbsp;*<br>
        &nbsp;* There is also a hook called "update_mmu_cache()" that
        architectures<br>
        &nbsp;* with external mmu caches can use to update those (ie the Sparc
        or<br>
        &nbsp;* PowerPC hashed page tables that act as extended TLBs).<br>
        &nbsp;*<br>
        &nbsp;* Note the "page_table_lock". It is to protect against kswapd
        removing<br>
        &nbsp;* pages from under us. Note that kswapd only ever _removes_ pages,
        never<br>
        &nbsp;* adds them. As such, once we have noticed that the page is not
        present,<br>
        &nbsp;* we can drop the lock early.<br>
        &nbsp;*<br>
        &nbsp;* The adding of pages is protected by the MM semaphore (which we
        hold),<br>
        &nbsp;* so we don't need to worry about a page being suddenly been added
        into<br>
        &nbsp;* our VM.<br>
        &nbsp;*/<br>
        static inline int handle_pte_fault(struct mm_struct *mm,<br>
        &nbsp;&nbsp; &nbsp;struct vm_area_struct * vma, unsigned long address,<br>
        &nbsp;&nbsp; &nbsp;int write_access, pte_t * pte)<br>
        {<br>
        &nbsp;&nbsp; &nbsp;pte_t entry;<br>
        <br>
        &nbsp;&nbsp; &nbsp;/*<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -