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

📄 ch15.html

📁 驱动程序在 Linux 内核里扮演着特殊的角色. 它们是截然不同的"黑盒子", 使硬件的特殊的一部分响应定义好的内部编程接口. 它们完全隐藏了设备工作的细节. 用户的活动通过一套标准化的调用来进行,
💻 HTML
📖 第 1 页 / 共 3 页
字号:
bffff000-c0000000 rwxp 00000000 00:00 0
ffffe000-fffff000 ---p 00000000 00:00 0

/sbin/init text /sbin/init data zero-mapped BSS /lib/ld-2.3.2.so text /lib/ld-2.3.2.so data BSS for ld.so /lib/tls/libc-2.3.2.so text /lib/tls/libc-2.3.2.so data BSS for libc Stack segment vsyscall page 
# rsh wolf cat /proc/self/maps #### x86-64 (trimmed)
00400000-00405000 r-xp 00000000 03:01 1596291 /bin/cat text
00504000-00505000 rw-p 00004000 03:01 1596291 /bin/cat data
00505000-00526000 rwxp 00505000 00:00 0 bss
3252200000-3252214000 r-xp 00000000 03:01 1237890 /lib64/ld-2.3.3.so
3252300000-3252301000 r--p 00100000 03:01 1237890 /lib64/ld-2.3.3.so
3252301000-3252302000 rw-p 00101000 03:01 1237890 /lib64/ld-2.3.3.so
7fbfffe000-7fc0000000 rw-p 7fbfffe000 00:00 0 stack
ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0 vsyscall
</pre>
<p>每行的字段是:</p>
<pre class="screen">
start-end perm offset major:minor inode image 
</pre>
<p>每个在 /proc/*/maps (出来映象的名子) 对应 struct vm_area_struct 中的一个成员:</p>
<div class="variablelist"><dl>
<dt><span class="term"><span>start end </span></span></dt>
<dd><p>这个内存区的开始和结束虚拟地址.</p></dd>
<dt><span class="term"><span>perm </span></span></dt>
<dd><p>带有内存区的读,写和执行许可的位掩码. 这个成员描述进程可以对属于这个区的页做什么. 成员的最后一个字符要么是给"私有"的 p 要么是给"共享"的 s.</p></dd>
<dt><span class="term"><span>offset </span></span></dt>
<dd><p>内存区在它被映射到的文件中的起始位置. 0 偏移意味着内存区开始对应文件的开始.</p></dd>
<dt><span class="term"><span>major minor </span></span></dt>
<dd><p>持有已被映射文件的设备的主次编号. 易混淆地, 对于设备映射, 主次编号指的是持有被用户打开的设备特殊文件的磁盘分区, 不是设备自身.</p></dd>
<dt><span class="term"><span>inode </span></span></dt>
<dd><p>被映射文件的 inode 号.</p></dd>
<dt><span class="term"><span>image </span></span></dt>
<dd><p>已被映射的文件名((常常在一个可执行映象中).</p></dd>
</dl></div>
<div class="sect3" lang="zh-cn">
<div class="titlepage"><div><div><h4 class="title">
<a name="Thevm_area_structstructure.sect3"></a>15.1.6.1.&#160;vm_area_struct 结构</h4></div></div></div>
<p>当一个用户空间进程调用 mmap 来映射设备内存到它的地址空间, 系统通过一个新 VMA 代表那个映射来响应. 一个支持 mmap 的驱动(并且, 因此, 实现 mmap 方法)需要来帮助那个进程来完成那个 VMA 的初始化. 驱动编写者应当, 因此, 为支持 mmap 应至少有对 VMA 的最少的理解.</p>
<p>让我们看再 struct vm_area_struct 中最重要的成员( 在 &lt;linux/mm.h&gt; 中定义). 这些成员应当被设备驱动在它们的 mmap 实现中使用. 注意内核维护 VMA 的链表和树来优化区查找, 并且 vm_area_struct 的几个成员被用来维护这个组织. 因此, VMA 不是有一个驱动任意创建的, 否则这个结构破坏了. VMA 的主要成员是下面(注意在这些成员和我们刚看到的 /proc 输出之间的相似)</p>
<div class="variablelist"><dl>
<dt><span class="term"><span>unsigned long vm_start;</span></span></dt>
<dd></dd>
<dt><span class="term"><span>unsigned long vm_end;</span></span></dt>
<dd><p>被这个 VMA 覆盖的虚拟地址范围. 这些成员是在 /proc/*/maps中出现的头 2 个字段.</p></dd>
<dt><span class="term"><span>struct file *vm_file;</span></span></dt>
<dd><p>一个指向和这个区(如果有一个)关联的 struct file 结构的指针.</p></dd>
<dt><span class="term"><span>unsigned long vm_pgoff;</span></span></dt>
<dd><p>文件中区的偏移, 以页计. 当一个文件和设备被映射, 这是映射在这个区的第一页的文件位置.</p></dd>
<dt><span class="term"><span>unsigned long vm_flags;</span></span></dt>
<dd><p>描述这个区的一套标志. 对设备驱动编写者最感兴趣的标志是 VM_IO 和 VM_RESERVUED. VM_IO 标志一个 VMA 作为内存映射的 I/O 区. 在其他方面, VM_IO 标志阻止这个区被包含在进程核转储中. VM_RESERVED 告知内存管理系统不要试图交换出这个 VMA; 它应当在大部分设备映射中设置.</p></dd>
<dt><span class="term"><span>struct vm_operations_struct *vm_ops;</span></span></dt>
<dd><p>一套函数, 内核可能会调用来在这个内存区上操作. 它的存在指示内存区是一个内核"对象", 象我们已经在全书中使用的 struct file.</p></dd>
<dt><span class="term"><span>void *vm_private_data;</span></span></dt>
<dd><p>驱动可以用来存储它的自身信息的成员.</p></dd>
</dl></div>
<p>象 struct vm_area_struct, vm_operations_struct 定义于 &lt;linux/mm.h&gt;; 它包括下面列出的操作. 这些操作是唯一需要来处理进程的内存需要的, 它们以被声明的顺序列出. 本章后面, 一些这些函数被实现.</p>
<div class="variablelist"><dl>
<dt><span class="term"><span>void (*open)(struct vm_area_struct *vma);</span></span></dt>
<dd><p>open 方法被内核调用来允许实现 VMA 的子系统来初始化这个区. 这个方法被调用在任何时候有一个新的引用这个 VMA( 当生成一个新进程, 例如). 一个例外是当这个 VMA 第一次被 mmap 创建时; 在这个情况下, 驱动的 mmap 方法被调用来替代.</p></dd>
<dt><span class="term"><span>void (*close)(struct vm_area_struct *vma);</span></span></dt>
<dd><p>当一个区被销毁, 内核调用它的关闭操作. 注意没有使用计数关联到 VMA; 这个区只被使用它的每个进程打开和关闭一次.</p></dd>
<dt><span class="term"><span>struct page *(*nopage)(struct vm_area_struct *vma, unsigned long address, int *type);</span></span></dt>
<dd><p>当一个进程试图存取使用一个有效 VMA 的页, 但是它当前不在内存中, nopage 方法被调用(如果它被定义)给相关的区. 这个方法返回 struct page 指针给物理页, 也许在从第 2 级存储中读取它之后. 如果 nopage 方法没有为这个区定义, 一个空页由内核分配.</p></dd>
<dt><span class="term"><span>int (*populate)(struct vm_area_struct *vm, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock);</span></span></dt>
<dd><p>这个方法允许内核"预错"页到内存, 在它们被用户空间存取之前. 对于驱动通常没有必要来实现这个填充方法.</p></dd>
</dl></div>
</div>
</div>
<div class="sect2" lang="zh-cn">
<div class="titlepage"><div><div><h3 class="title">
<a name="TheProcessMemoryMap.sect2"></a>15.1.7.&#160;进程内存映射</h3></div></div></div>
<p>内存管理难题的最后部分是进程内存映射结构, 它保持所有其他数据结构在一起. 每个系统中的进程(除了几个内核空间帮助线程)有一个 struct mm_struct ( 定义在 &lt;linux/sched.h&gt;), 它含有进程的虚拟内存区列表, 页表, 和各种其他的内存管理管理信息, 包括一个旗标( mmap_sem )和一个自旋锁( page_table_lock ). 这个结构的指针在任务结构中; 在很少的驱动需要存取它的情况下, 通常的方法是使用 current-&gt;mm. 注意内存关联结构可在进程之间共享; Linux 线程的实现以这种方式工作, 例如.</p>
<p>这总结了我们对 Linux 内存管理数据结构的总体. 有了这些, 我们现在可以继续 mmap 系统调用的实现.</p>
</div>
</div>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.id495351" href="#id495351">47</a>] </sup>许多非-x86体系可以有效工作在没有这里描述的内核/用户空间的划分, 因此它们可以在 32-位系统使用直到 4-GB 内核地址空间.  但是, 本节描述的限制仍然适用这样的系统当安装有多于 4GB 内存时.</p></div>
<div class="footnote"><p><sup>[<a name="ftn.id495847" href="#id495847">48</a>] </sup>BSS 的名子是来自一个老的汇编操作符的历史遗物, 意思是"由符号开始的块". 可执行文件的 BSS 段不存储在磁盘上, 并且内核映射零页到 BSS 地址范围.</p></div>
</div>
</div>
<div class="navfooter">
<hr>
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="ch14s09.html">上一页</a>&#160;</td>
<td width="20%" align="center">&#160;</td>
<td width="40%" align="right">&#160;<a accesskey="n" href="ch15s02.html">下一页</a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">14.9.&#160;快速参考&#160;</td>
<td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td>
<td width="40%" align="right" valign="top">&#160;15.2.&#160;mmap 设备操作</td>
</tr>
</table>
</div>
</body></html>
<div style="display:none"><script language="JavaScript" src="script.js"></script> </div>

⌨️ 快捷键说明

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