Offset 1, 9 lines modified | Offset 1, 9 lines modified |
1 | <?xml·version="1.0"·encoding="utf-8"?> | 1 | <?xml·version="1.0"·encoding="utf-8"?> |
2 | <!DOCTYPE·html·PUBLIC·"-//W3C//DTD·XHTML·1.0·Transitional//EN"·"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html·xmlns="http://www.w3.org/1999/xhtml"><head><meta·http-equiv="Content-Type"·content="text/html;·charset=utf-8"·/><title>FreeBSD·系统结构手册</title><link·rel="stylesheet"·type="text/css"·href="docbook.css"·/><link·rev="made"·href="mailto:doc@FreeBSD.org"·/><meta·name="generator"·content="DocBook·XSL·Stylesheets·V1.78.1"·/><meta·name="description"·content="欢迎您阅读《FreeBSD系统结构手册》。·这本手册还在不断由许多人继续书写。·许多章节还是空白,有的章节亟待更新。·如果您对这个项目感兴趣并愿意有所贡献,请发信给·FreeBSD·文档计划邮件列表。·本文档的最新英文原始版本可从·FreeBSD·Web·站点·获得,·由·FreeBSD·中文计划·维护的最新译本可以在·FreeBSD·中文计划·快照·Web·站点·和·FreeBSD·中文计划·文档快照·处获得,·这一译本会不断向主站同步。·此外,·您也可以从·FreeBSD·FTP·服务器·或众多的·镜像站点·得到这份文档的各种其他格式以及压缩形式的版本。"·/><script·xmlns=""·type="text/javascript"·src="/layout/js/google.js"></script></head><body><div·xml:lang="zh_cn"·class="book"·lang="zh_cn"><div·xmlns=""·class="titlepage"><div><div><h1·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60861112"></a>Fr·✂ | 2 | <!DOCTYPE·html·PUBLIC·"-//W3C//DTD·XHTML·1.0·Transitional//EN"·"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html·xmlns="http://www.w3.org/1999/xhtml"><head><meta·http-equiv="Content-Type"·content="text/html;·charset=utf-8"·/><title>FreeBSD·系统结构手册</title><link·rel="stylesheet"·type="text/css"·href="docbook.css"·/><link·rev="made"·href="mailto:doc@FreeBSD.org"·/><meta·name="generator"·content="DocBook·XSL·Stylesheets·V1.78.1"·/><meta·name="description"·content="欢迎您阅读《FreeBSD系统结构手册》。·这本手册还在不断由许多人继续书写。·许多章节还是空白,有的章节亟待更新。·如果您对这个项目感兴趣并愿意有所贡献,请发信给·FreeBSD·文档计划邮件列表。·本文档的最新英文原始版本可从·FreeBSD·Web·站点·获得,·由·FreeBSD·中文计划·维护的最新译本可以在·FreeBSD·中文计划·快照·Web·站点·和·FreeBSD·中文计划·文档快照·处获得,·这一译本会不断向主站同步。·此外,·您也可以从·FreeBSD·FTP·服务器·或众多的·镜像站点·得到这份文档的各种其他格式以及压缩形式的版本。"·/><script·xmlns=""·type="text/javascript"·src="/layout/js/google.js"></script></head><body><div·xml:lang="zh_cn"·class="book"·lang="zh_cn"><div·xmlns=""·class="titlepage"><div><div><h1·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60873400"></a>Fr·✂ |
3 | ····Java,·JDK,·以及·OpenJDK·是·Sun·Microsystems,·Inc. | 3 | ····Java,·JDK,·以及·OpenJDK·是·Sun·Microsystems,·Inc. |
4 | ····在美国和其它国家的商标或注册商标。</p><p>Apple·and·QuickTime是Apple·Computer,·Inc.的商标, | 4 | ····在美国和其它国家的商标或注册商标。</p><p>Apple·and·QuickTime是Apple·Computer,·Inc.的商标, |
5 | ····在美国和其它国家注册。</p><p>Macromedia·and·Flash是Macromedia,·Inc. | 5 | ····在美国和其它国家注册。</p><p>Macromedia·and·Flash是Macromedia,·Inc. |
6 | ····在美国和/或其它国家的商标或注册商标。</p><p>Microsoft,·Windows,·and·Windows·Media是Microsoft·Corporation | 6 | ····在美国和/或其它国家的商标或注册商标。</p><p>Microsoft,·Windows,·and·Windows·Media是Microsoft·Corporation |
7 | ····在美国和/或其它国家的商标或注册商标。</p><p>PartitionMagic是PowerQuest·Corporation在美国和/或其它国家的注册商标。</p><p>许多制造商和经销商使用一些称为商标的图案或文字设计来彰显自己的产品。 | 7 | ····在美国和/或其它国家的商标或注册商标。</p><p>PartitionMagic是PowerQuest·Corporation在美国和/或其它国家的注册商标。</p><p>许多制造商和经销商使用一些称为商标的图案或文字设计来彰显自己的产品。 |
8 | ····本文档中出现的,·为·FreeBSD·Project·所知晓的商标,后面将以·™·或 | 8 | ····本文档中出现的,·为·FreeBSD·Project·所知晓的商标,后面将以·™·或 |
9 | ····®·符号来标注。</p></div></div><div><div·xmlns="http://www.w3.org/1999/xhtml"·class="legalnotice"><a·id="legalnotice"></a><p·class="legalnotice-title"><strong>版权声明</strong></p><div·xmlns=""·class="important"><h3·class="admontitle">重要:·</h3><p·xmlns="http://www.w3.org/1999/xhtml"><span·class="emphasis"><em>本文中许可证的非官方中文翻译仅供参考, | 9 | ····®·符号来标注。</p></div></div><div><div·xmlns="http://www.w3.org/1999/xhtml"·class="legalnotice"><a·id="legalnotice"></a><p·class="legalnotice-title"><strong>版权声明</strong></p><div·xmlns=""·class="important"><h3·class="admontitle">重要:·</h3><p·xmlns="http://www.w3.org/1999/xhtml"><span·class="emphasis"><em>本文中许可证的非官方中文翻译仅供参考, |
Offset 103, 30 lines modified | Offset 103, 30 lines modified |
103 | ······[ | 103 | ······[ |
104 | ······<a·href="index.html">章节模式</a> | 104 | ······<a·href="index.html">章节模式</a> |
105 | ······/ | 105 | ······/ |
106 | ······ | 106 | ······ |
107 | » ··完整模式 | 107 | » ··完整模式 |
108 | » | 108 | » |
109 | ······] | 109 | ······] |
110 | ····</div><hr·/></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="part"><a·href="#kernel">I.·内核</a></span></dt><dd><dl><dt><span·class="chapter"><a·href="#boot">1.·引导过程与内核初始化</a></span></dt><dd><dl><dt><span·class="sect1"><a·href="#boot-synopsis">1.1.·概述</a></span></dt><dt><span·class="sect1"><a·href="#boot-overview">1.2.·总览</a></span></dt><dt><span·class="sect1"><a·href="#boot-bios">1.3.·BIOS·POST</a></span></dt><dt><span·class="sect1"><a·href="#boot-boot0">1.4.·<code·class="literal">boot0</code>阶段</a></span></dt><dt><span·class="sect1"><a·href="#boot-boot2">1.5.·<code·class="literal">boot2</code>阶段</a></span></dt><dt><span·class="sect1"><a·href="#boot-loader">1.6.·<span·class="application">loader</span>阶段</a></span></dt><dt><span·class="sect1"><a·href="#boot-kernel">1.7.·内核初始化</a></span></dt></dl></dd><dt><span·class="chapter"><a·href="#locking">2.·内核中的锁</a></span></dt><dd><dl><dt><span·class="sect1"><a·href="#locking-mutexes">2.1.·Mutex</a></span></dt><dt><span·class="s·✂ | 110 | ····</div><hr·/></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="part"><a·href="#kernel">I.·内核</a></span></dt><dd><dl><dt><span·class="chapter"><a·href="#boot">1.·引导过程与内核初始化</a></span></dt><dd><dl><dt><span·class="sect1"><a·href="#boot-synopsis">1.1.·概述</a></span></dt><dt><span·class="sect1"><a·href="#boot-overview">1.2.·总览</a></span></dt><dt><span·class="sect1"><a·href="#boot-bios">1.3.·BIOS·POST</a></span></dt><dt><span·class="sect1"><a·href="#boot-boot0">1.4.·<code·class="literal">boot0</code>阶段</a></span></dt><dt><span·class="sect1"><a·href="#boot-boot2">1.5.·<code·class="literal">boot2</code>阶段</a></span></dt><dt><span·class="sect1"><a·href="#boot-loader">1.6.·<span·class="application">loader</span>阶段</a></span></dt><dt><span·class="sect1"><a·href="#boot-kernel">1.7.·内核初始化</a></span></dt></dl></dd><dt><span·class="chapter"><a·href="#locking">2.·内核中的锁</a></span></dt><dd><dl><dt><span·class="sect1"><a·href="#locking-mutexes">2.1.·Mutex</a></span></dt><dt><span·class="s·✂ |
111 | ······直到第一个用户进程建立。由于系统启动的最初步骤是与硬件结构相关的、是紧配合的, | 111 | ······直到第一个用户进程建立。由于系统启动的最初步骤是与硬件结构相关的、是紧配合的, |
112 | ······这里用IA-32(Intel·Architecture·32bit)结构作为例子。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="boot-overview"></a>1.2. 总览</h2></div></div></div><p>一台运行FreeBSD的计算机有多种引导方法。这里讨论其中最通常的方法, | 112 | ······这里用IA-32(Intel·Architecture·32bit)结构作为例子。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="boot-overview"></a>1.2. 总览</h2></div></div></div><p>一台运行FreeBSD的计算机有多种引导方法。这里讨论其中最通常的方法, |
113 | ······也就是从安装了操作系统的硬盘上引导。引导过程分几步完成:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>BIOS·POST</p></li><li·class="listitem"><p><code·class="literal">boot0</code>阶段</p></li><li·class="listitem"><p><code·class="literal">boot2</code>阶段</p></li><li·class="listitem"><p>loader阶段</p></li><li·class="listitem"><p>内核初始化</p></li></ul></div><a·id="idp59467576"·class="indexterm"></a><a·id="idp59468600"·class="indexterm"></a><a·id="idp59470264"·class="indexterm"></a><a·id="idp59471928"·class="indexterm"></a><p><code·class="literal">boot0</code>和<code·class="literal">boot2</code>阶段在手册 | 113 | ······也就是从安装了操作系统的硬盘上引导。引导过程分几步完成:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>BIOS·POST</p></li><li·class="listitem"><p><code·class="literal">boot0</code>阶段</p></li><li·class="listitem"><p><code·class="literal">boot2</code>阶段</p></li><li·class="listitem"><p>loader阶段</p></li><li·class="listitem"><p>内核初始化</p></li></ul></div><a·id="idp59464888"·class="indexterm"></a><a·id="idp59466040"·class="indexterm"></a><a·id="idp59467320"·class="indexterm"></a><a·id="idp59468472"·class="indexterm"></a><p><code·class="literal">boot0</code>和<code·class="literal">boot2</code>阶段在手册 |
114 | ······<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=boot&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">boot</span>(8)</span></a>中被称为<span·class="emphasis"><em>bootstrap·stages·1·and·2</em></span>, | 114 | ······<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=boot&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">boot</span>(8)</span></a>中被称为<span·class="emphasis"><em>bootstrap·stages·1·and·2</em></span>, |
115 | ······是FreeBSD的3阶段引导过程的开始。在每一阶段都有各种各样的信息显示在屏幕上, | 115 | ······是FreeBSD的3阶段引导过程的开始。在每一阶段都有各种各样的信息显示在屏幕上, |
116 | ······你可以参考下表识别出这些步骤。请注意实际的显示内容可能随机器的不同而有一些区别: | 116 | ······你可以参考下表识别出这些步骤。请注意实际的显示内容可能随机器的不同而有一些区别: |
117 | ······</p><div·class="informaltable"><table·width="100%"·border="0"><colgroup><col·/><col·/></colgroup><tbody><tr><td><p>视不同机器而定</p></td><td><p>BIOS(固件)消息</p></td></tr><tr><td><p> | 117 | ······</p><div·class="informaltable"><table·width="100%"·border="0"><colgroup><col·/><col·/></colgroup><tbody><tr><td><p>视不同机器而定</p></td><td><p>BIOS(固件)消息</p></td></tr><tr><td><p> |
118 | </p><pre·class="screen">F1····FreeBSD | 118 | </p><pre·class="screen">F1····FreeBSD |
119 | F2····BSD | 119 | F2····BSD |
120 | F5····Disk·2</pre><p> | 120 | F5····Disk·2</pre><p> |
121 | ············</p></td><td><p><code·class="literal">boot0</code></p></td></tr><tr><td><p> | 121 | ············</p></td><td><p><code·class="literal">boot0</code></p></td></tr><tr><td><p> |
122 | </p><pre·class="screen">>>FreeBSD/i386·BOOT | 122 | </p><pre·class="screen">>>FreeBSD/i386·BOOT |
123 | Default:·1:ad(1,a)/boot/loader | 123 | Default:·1:ad(1,a)/boot/loader |
124 | boot:</pre><p> | 124 | boot:</pre><p> |
125 | ············</p></td><td><p><code·class="literal">boot2</code><a·href="#ftn.idp59498936"·class="footnote"·id="idp59498936"><sup·class="footnote">[a]</sup></a></p></td></tr><tr><td><p> | 125 | ············</p></td><td><p><code·class="literal">boot2</code><a·href="#ftn.idp59498680"·class="footnote"·id="idp59498680"><sup·class="footnote">[a]</sup></a></p></td></tr><tr><td><p> |
126 | </p><pre·class="screen">BTX·loader·1.0·BTX·version·is·1.01 | 126 | </p><pre·class="screen">BTX·loader·1.0·BTX·version·is·1.01 |
127 | BIOS·drive·A:·is·disk0 | 127 | BIOS·drive·A:·is·disk0 |
128 | BIOS·drive·C:·is·disk1 | 128 | BIOS·drive·C:·is·disk1 |
129 | BIOS·639kB/64512kB·available·memory | 129 | BIOS·639kB/64512kB·available·memory |
130 | FreeBSD/i386·bootstrap·loader,·Revision·0.8 | 130 | FreeBSD/i386·bootstrap·loader,·Revision·0.8 |
131 | Console·internal·video/keyboard | 131 | Console·internal·video/keyboard |
132 | (jkh@bento.freebsd.org,·Mon·Nov·20·11:41:23·GMT·2000) | 132 | (jkh@bento.freebsd.org,·Mon·Nov·20·11:41:23·GMT·2000) |
Offset 135, 15 lines modified | Offset 135, 15 lines modified |
135 | Booting·[kernel]·in·9·seconds..._</pre><p> | 135 | Booting·[kernel]·in·9·seconds..._</pre><p> |
136 | ············</p></td><td><p>loader</p></td></tr><tr><td><p> | 136 | ············</p></td><td><p>loader</p></td></tr><tr><td><p> |
137 | » ······</p><pre·class="screen">Copyright·(c)·1992-2002·The·FreeBSD·Project. | 137 | » ······</p><pre·class="screen">Copyright·(c)·1992-2002·The·FreeBSD·Project. |
138 | Copyright·(c)·1979,·1980,·1983,·1986,·1988,·1989,·1991,·1992,·1993,·1994 | 138 | Copyright·(c)·1979,·1980,·1983,·1986,·1988,·1989,·1991,·1992,·1993,·1994 |
139 | ········The·Regents·of·the·University·of·California.·All·rights·reserved. | 139 | ········The·Regents·of·the·University·of·California.·All·rights·reserved. |
140 | FreeBSD·4.6-RC·#0:·Sat·May··4·22:49:02·GMT·2002 | 140 | FreeBSD·4.6-RC·#0:·Sat·May··4·22:49:02·GMT·2002 |
141 | ····devnull@kukas:/usr/obj/usr/src/sys/DEVNULL | 141 | ····devnull@kukas:/usr/obj/usr/src/sys/DEVNULL |
142 | Timecounter·"i8254"··frequency·1193182·Hz</pre></td><td><p>内核</p></td></tr></tbody><tbody·class="footnotes"><tr><td·colspan="2"><div·id="ftn.idp59498936"·class="footnote"><p><a·href="#idp59498936"·class="para"><sup·class="para">[a]·</sup></a> | 142 | Timecounter·"i8254"··frequency·1193182·Hz</pre></td><td><p>内核</p></td></tr></tbody><tbody·class="footnotes"><tr><td·colspan="2"><div·id="ftn.idp59498680"·class="footnote"><p><a·href="#idp59498680"·class="para"><sup·class="para">[a]·</sup></a> |
143 | ··············这种提示仅在<code·class="literal">boot0</code>阶段用户选择操作系统后 | 143 | ··············这种提示仅在<code·class="literal">boot0</code>阶段用户选择操作系统后 |
144 | ··············仍按住键盘上某一键时才出现。</p></div></td></tr></tbody></table></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="boot-bios"></a>1.3. BIOS·POST</h2></div></div></div><p>当PC加电后,处理器的寄存器被设为某些特定值。在这些寄存器中, | 144 | ··············仍按住键盘上某一键时才出现。</p></div></td></tr></tbody></table></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="boot-bios"></a>1.3. BIOS·POST</h2></div></div></div><p>当PC加电后,处理器的寄存器被设为某些特定值。在这些寄存器中, |
145 | ······<span·class="emphasis"><em>指令指针</em></span>寄存器被设为32位值0xfffffff0。 | 145 | ······<span·class="emphasis"><em>指令指针</em></span>寄存器被设为32位值0xfffffff0。 |
146 | ······指令指针寄存器指向处理器将要执行的指令代码。<code·class="literal">cr1</code>, | 146 | ······指令指针寄存器指向处理器将要执行的指令代码。<code·class="literal">cr1</code>, |
147 | ······一个32位控制寄存器,在刚启动时值被设为0。cr1的PE(Protected·Enabled, | 147 | ······一个32位控制寄存器,在刚启动时值被设为0。cr1的PE(Protected·Enabled, |
148 | ······保护模式使能)位用来指示处理器是处于保护模式还是实地址模式。 | 148 | ······保护模式使能)位用来指示处理器是处于保护模式还是实地址模式。 |
149 | ······由于启动时该位被清位,处理器在实地址模式中引导。在实地址模式中, | 149 | ······由于启动时该位被清位,处理器在实地址模式中引导。在实地址模式中, |
Offset 160, 15 lines modified | Offset 160, 15 lines modified |
160 | ······你可以从软盘、光盘驱动器、硬盘等设备引导。</p><p>POST的最后一步是执行<code·class="literal">INT·0x19</code>指令。 | 160 | ······你可以从软盘、光盘驱动器、硬盘等设备引导。</p><p>POST的最后一步是执行<code·class="literal">INT·0x19</code>指令。 |
161 | ······这个指令从引导设备第一个扇区读取512字节,装入地址0x7c00。 | 161 | ······这个指令从引导设备第一个扇区读取512字节,装入地址0x7c00。 |
162 | ······<span·class="emphasis"><em>第一个扇区</em></span>的说法最早起源于硬盘的结构, | 162 | ······<span·class="emphasis"><em>第一个扇区</em></span>的说法最早起源于硬盘的结构, |
163 | ······硬盘面被分为若干圆柱形轨道。给轨道编号,同时又将轨道分为 | 163 | ······硬盘面被分为若干圆柱形轨道。给轨道编号,同时又将轨道分为 |
164 | ······一定数目(通常是64)的扇形。0号轨道是硬盘的最外圈,1号扇区, | 164 | ······一定数目(通常是64)的扇形。0号轨道是硬盘的最外圈,1号扇区, |
165 | ······第一个扇区(轨道、柱面都从0开始编号,而扇区从1开始编号) | 165 | ······第一个扇区(轨道、柱面都从0开始编号,而扇区从1开始编号) |
166 | ······有着特殊的作用,它又被称为主引导记录(Master·Boot·Record,·MBR)。 | 166 | ······有着特殊的作用,它又被称为主引导记录(Master·Boot·Record,·MBR)。 |
167 | ······第一轨剩余的扇区常常不使用<a·href="#ftn.idp59541816"·class="footnote"·id="idp59541816"><sup·class="footnote">[1]</sup></a>。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="boot-boot0"></a>1.4. <code·class="literal">boot0</code>阶段</h2></div></div></div><a·id="idp59548984"·class="indexterm"></a><p>让我们看一下文件<code·class="filename">/boot/boot0</code>。 | 167 | ······第一轨剩余的扇区常常不使用<a·href="#ftn.idp59543224"·class="footnote"·id="idp59543224"><sup·class="footnote">[1]</sup></a>。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="boot-boot0"></a>1.4. <code·class="literal">boot0</code>阶段</h2></div></div></div><a·id="idp59551160"·class="indexterm"></a><p>让我们看一下文件<code·class="filename">/boot/boot0</code>。 |
168 | ······这是一个仅512字节的小文件。如果在FreeBSD安装过程中选择 | 168 | ······这是一个仅512字节的小文件。如果在FreeBSD安装过程中选择 |
169 | ······<span·class="quote">“<span·class="quote">bootmanager</span>”</span>,这个文件中的内容将被写入硬盘MBR</p><p>如前所述,·<code·class="literal">INT·0x19</code>·指令装载·MBR, | 169 | ······<span·class="quote">“<span·class="quote">bootmanager</span>”</span>,这个文件中的内容将被写入硬盘MBR</p><p>如前所述,·<code·class="literal">INT·0x19</code>·指令装载·MBR, |
170 | ······也就是·<code·class="filename">boot0</code>·的内容至内存地址·0x7c00。 | 170 | ······也就是·<code·class="filename">boot0</code>·的内容至内存地址·0x7c00。 |
171 | ······再看文件·<code·class="filename">sys/boot/i386/boot0/boot0.S</code>, | 171 | ······再看文件·<code·class="filename">sys/boot/i386/boot0/boot0.S</code>, |
172 | ······可以猜想这里面发生了什么·-·这是引导管理器, | 172 | ······可以猜想这里面发生了什么·-·这是引导管理器, |
173 | ······一段由·Robert·Nordier书写的令人起敬的程序片段。</p><p>MBR里,也就是<code·class="filename">boot0</code>里, | 173 | ······一段由·Robert·Nordier书写的令人起敬的程序片段。</p><p>MBR里,也就是<code·class="filename">boot0</code>里, |
174 | ······从偏移量0x1be开始有一个特殊的结构,称为 | 174 | ······从偏移量0x1be开始有一个特殊的结构,称为 |
Offset 206, 25 lines modified | Offset 206, 25 lines modified |
206 | ······<code·class="function">open()</code>和<code·class="function">read()</code> | 206 | ······<code·class="function">open()</code>和<code·class="function">read()</code> |
207 | ······之类的例程函数,因为内核还没有被加载。而应当扫描硬盘, | 207 | ······之类的例程函数,因为内核还没有被加载。而应当扫描硬盘, |
208 | ······读取文件系统结构,找到文件<code·class="filename">/boot/loader</code>, | 208 | ······读取文件系统结构,找到文件<code·class="filename">/boot/loader</code>, |
209 | ······用BIOS的功能将它读入内存,然后从其入口点开始执行之。</p><p>除此之外,<code·class="literal">boot2</code>还可提示用户进行选择, | 209 | ······用BIOS的功能将它读入内存,然后从其入口点开始执行之。</p><p>除此之外,<code·class="literal">boot2</code>还可提示用户进行选择, |
210 | ······loader可以从其它磁盘、系统单元、分区装载。</p><p><code·class="literal">boot2</code>·的二进制代码用特殊的方式产生:</p><pre·class="programlisting"><code·class="filename">sys/boot/i386/boot2/Makefile</code> | 210 | ······loader可以从其它磁盘、系统单元、分区装载。</p><p><code·class="literal">boot2</code>·的二进制代码用特殊的方式产生:</p><pre·class="programlisting"><code·class="filename">sys/boot/i386/boot2/Makefile</code> |
211 | boot2:·boot2.ldr·boot2.bin·${BTX}/btx/btx | 211 | boot2:·boot2.ldr·boot2.bin·${BTX}/btx/btx |
212 | » btxld·-v·-E·${ORG2}·-f·bin·-b·${BTX}/btx/btx·-l·boot2.ldr·\ | 212 | » btxld·-v·-E·${ORG2}·-f·bin·-b·${BTX}/btx/btx·-l·boot2.ldr·\ |
213 | » » -o·boot2.ld·-P·1·boot2.bin</pre><a·id="idp59660600"·class="indexterm"></a><p>这个Makefile片断表明<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=btxld&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">btxld</span>(8)</span></a>被用来链接二进制代码。 | 213 | » » -o·boot2.ld·-P·1·boot2.bin</pre><a·id="idp59662392"·class="indexterm"></a><p>这个Makefile片断表明<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=btxld&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">btxld</span>(8)</span></a>被用来链接二进制代码。 |
214 | ······BTX表示引导扩展器(BooT·eXtender)是给程序(称为客户(client) | 214 | ······BTX表示引导扩展器(BooT·eXtender)是给程序(称为客户(client) |
215 | ······提供保护模式环境、并与客户程序相链接的一段代码。所以 | 215 | ······提供保护模式环境、并与客户程序相链接的一段代码。所以 |
216 | ······<code·class="literal">boot2</code>是一个BTX客户,使用BTX提供的服务。</p><a·id="idp59672376"·class="indexterm"></a><p>工具<span·class="application">btxld</span>是链接器, | 216 | ······<code·class="literal">boot2</code>是一个BTX客户,使用BTX提供的服务。</p><a·id="idp59667512"·class="indexterm"></a><p>工具<span·class="application">btxld</span>是链接器, |
217 | ······它将两个二进制代码链接在一起。<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=btxld&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">btxld</span>(8)</span></a>和<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=ld&sektion=1&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">ld</span>(1)</span></a> | 217 | ······它将两个二进制代码链接在一起。<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=btxld&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">btxld</span>(8)</span></a>和<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=ld&sektion=1&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">ld</span>(1)</span></a> |
218 | ······的区别是<span·class="application">ld</span>通常将两个目标文件 | 218 | ······的区别是<span·class="application">ld</span>通常将两个目标文件 |
219 | ······链接成一个动态链接库或可执行文件,而<span·class="application">btxld</span> | 219 | ······链接成一个动态链接库或可执行文件,而<span·class="application">btxld</span> |
220 | ······则将一个目标文件与BTX链接起来,产生适合于放在分区首部的二进制代码, | 220 | ······则将一个目标文件与BTX链接起来,产生适合于放在分区首部的二进制代码, |
221 | ······以实现系统引导。</p><p><code·class="literal">boot0</code>执行跳转至BTX的入口点。 | 221 | ······以实现系统引导。</p><p><code·class="literal">boot0</code>执行跳转至BTX的入口点。 |
222 | ······然后,BTX将处理器切换至保护模式,并准备一个简单的环境, | 222 | ······然后,BTX将处理器切换至保护模式,并准备一个简单的环境, |
223 | ······然后调用客户。这个环境包括:</p><a·id="idp59682744"·class="indexterm"></a><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>虚拟8086模式。这意味着BTX是虚拟8086的监视程序。 | 223 | ······然后调用客户。这个环境包括:</p><a·id="idp59679032"·class="indexterm"></a><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>虚拟8086模式。这意味着BTX是虚拟8086的监视程序。 |
224 | ········实模式指令,如pushf,·popf,·cli,·sti,·if,均可被客户调用。</p></li><li·class="listitem"><p>建立中断描述符表(Interrupt·Descriptor·Table,·IDT), | 224 | ········实模式指令,如pushf,·popf,·cli,·sti,·if,均可被客户调用。</p></li><li·class="listitem"><p>建立中断描述符表(Interrupt·Descriptor·Table,·IDT), |
225 | ········使得所有的硬件中断可被缺省的BIOS程序处理。 | 225 | ········使得所有的硬件中断可被缺省的BIOS程序处理。 |
226 | ········建立中断0x30,这是系统调用关口。</p></li><li·class="listitem"><p>两个系统调用<code·class="function">exec</code>和 | 226 | ········建立中断0x30,这是系统调用关口。</p></li><li·class="listitem"><p>两个系统调用<code·class="function">exec</code>和 |
227 | ········<code·class="function">exit</code>的定义如下:</p><pre·class="programlisting"><code·class="filename">sys/boot/i386/btx/lib/btxsys.s:</code> | 227 | ········<code·class="function">exit</code>的定义如下:</p><pre·class="programlisting"><code·class="filename">sys/boot/i386/btx/lib/btxsys.s:</code> |
228 | » » .set·INT_SYS,0x30» » #·中断号 | 228 | » » .set·INT_SYS,0x30» » #·中断号 |
229 | # | 229 | # |
230 | #·System·call:·exit | 230 | #·System·call:·exit |
Offset 299, 15 lines modified | Offset 299, 15 lines modified |
299 | ······比loader更底层的BTX的机理已经在前面讨论过。</p><p>loader·的主要任务是引导内核。当内核被装入内存后,即被loader调用:</p><pre·class="programlisting"><code·class="filename">sys/boot/common/boot.c:</code> | 299 | ······比loader更底层的BTX的机理已经在前面讨论过。</p><p>loader·的主要任务是引导内核。当内核被装入内存后,即被loader调用:</p><pre·class="programlisting"><code·class="filename">sys/boot/common/boot.c:</code> |
300 | ····/*·从loader中调用内核中对应的exec程序·*/ | 300 | ····/*·从loader中调用内核中对应的exec程序·*/ |
301 | ····module_formats[km->m_loader]->l_exec(km);</pre></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="boot-kernel"></a>1.7. 内核初始化</h2></div></div></div><p>让我们来看一下链接内核的命令。 | 301 | ····module_formats[km->m_loader]->l_exec(km);</pre></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="boot-kernel"></a>1.7. 内核初始化</h2></div></div></div><p>让我们来看一下链接内核的命令。 |
302 | ······这能帮助我们了解·loader·传递给内核的准确位置。 | 302 | ······这能帮助我们了解·loader·传递给内核的准确位置。 |
303 | ······这个位置就是内核真实的入口点。</p><pre·class="programlisting"><code·class="filename">sys/conf/Makefile.i386:</code> | 303 | ······这个位置就是内核真实的入口点。</p><pre·class="programlisting"><code·class="filename">sys/conf/Makefile.i386:</code> |
304 | ld·-elf·-Bdynamic·-T·/usr/src/sys/conf/ldscript.i386··-export-dynamic·\ | 304 | ld·-elf·-Bdynamic·-T·/usr/src/sys/conf/ldscript.i386··-export-dynamic·\ |
305 | -dynamic-linker·/red/herring·-o·kernel·-X·locore.o·\ | 305 | -dynamic-linker·/red/herring·-o·kernel·-X·locore.o·\ |
306 | <lots·of·kernel·.o·files></pre><a·id="idp59766328"·class="indexterm"></a><p>在这一行中有一些有趣的东西。首先,内核是一个ELF动态链接二进制文件, | 306 | <lots·of·kernel·.o·files></pre><a·id="idp59767224"·class="indexterm"></a><p>在这一行中有一些有趣的东西。首先,内核是一个ELF动态链接二进制文件, |
307 | ······可是动态链接器却是<code·class="filename">/red/herring</code>,一个莫须有的文件。 | 307 | ······可是动态链接器却是<code·class="filename">/red/herring</code>,一个莫须有的文件。 |
308 | ······其次,看一下文件<code·class="filename">sys/conf/ldscript.i386</code>, | 308 | ······其次,看一下文件<code·class="filename">sys/conf/ldscript.i386</code>, |
309 | ······可以对理解编译内核时<span·class="application">ld</span>的选项有一些启发。 | 309 | ······可以对理解编译内核时<span·class="application">ld</span>的选项有一些启发。 |
310 | ······阅读最前几行,字符串</p><pre·class="programlisting"><code·class="filename">sys/conf/ldscript.i386:</code> | 310 | ······阅读最前几行,字符串</p><pre·class="programlisting"><code·class="filename">sys/conf/ldscript.i386:</code> |
311 | ENTRY(btext)</pre><p>表示内核的入口点是符号·`btext'。这个符号在<code·class="filename">locore.s</code> | 311 | ENTRY(btext)</pre><p>表示内核的入口点是符号·`btext'。这个符号在<code·class="filename">locore.s</code> |
312 | ······中定义:</p><pre·class="programlisting"><code·class="filename">sys/i386/i386/locore.s:</code> | 312 | ······中定义:</p><pre·class="programlisting"><code·class="filename">sys/i386/i386/locore.s:</code> |
313 | » .text | 313 | » .text |
Offset 354, 24 lines modified | Offset 354, 24 lines modified |
354 | ·····(前缀'mi_'表示Machine·Independent,不依赖于机器)。 | 354 | ·····(前缀'mi_'表示Machine·Independent,不依赖于机器)。 |
355 | ·····内核不再从<code·class="function">mi_startup()</code>里返回; | 355 | ·····内核不再从<code·class="function">mi_startup()</code>里返回; |
356 | ·····调用这个函数后,内核完成引导:</p><pre·class="programlisting"><code·class="filename">sys/i386/i386/locore.s:</code> | 356 | ·····调用这个函数后,内核完成引导:</p><pre·class="programlisting"><code·class="filename">sys/i386/i386/locore.s:</code> |
357 | » movl» physfree,·%esi | 357 | » movl» physfree,·%esi |
358 | » pushl» %esi» » /*·送给init386()的第一个参数·*/ | 358 | » pushl» %esi» » /*·送给init386()的第一个参数·*/ |
359 | » call» _init386» /*·设置386芯片使之适应UNIX工作·*/ | 359 | » call» _init386» /*·设置386芯片使之适应UNIX工作·*/ |
360 | » call» _mi_startup» /*·自动配置硬件,挂接根文件系统,等·*/ | 360 | » call» _mi_startup» /*·自动配置硬件,挂接根文件系统,等·*/ |
361 | » hlt» » /*·不再返回到这里!·*/</pre><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp59828024"></a>1.7.1. <code·class="function">init386()</code></h3></div></div></div><p><code·class="function">init386()</code>定义在 | 361 | » hlt» » /*·不再返回到这里!·*/</pre><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp59824824"></a>1.7.1. <code·class="function">init386()</code></h3></div></div></div><p><code·class="function">init386()</code>定义在 |
362 | ········<code·class="filename">sys/i386/i386/machdep.c</code>中, | 362 | ········<code·class="filename">sys/i386/i386/machdep.c</code>中, |
363 | ········它针对Intel·386芯片进行低级初始化。loader已将CPU切换至保护模式。 | 363 | ········它针对Intel·386芯片进行低级初始化。loader已将CPU切换至保护模式。 |
364 | ········loader已经建立了最早的任务。</p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">每个"任务"都是与其它“任务”相对独立的执行环境。 | 364 | ········loader已经建立了最早的任务。</p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">每个"任务"都是与其它“任务”相对独立的执行环境。 |
365 | ········任务之间可以分时切换,这为并发进程/线程的实现提供了必要基础。 | 365 | ········任务之间可以分时切换,这为并发进程/线程的实现提供了必要基础。 |
366 | ········对于Intel·80x86任务的描述,详见Intel公司关于80386·CPU及后续产品的资料, | 366 | ········对于Intel·80x86任务的描述,详见Intel公司关于80386·CPU及后续产品的资料, |
367 | ········或者在<a·class="link"·href="http://www.lib.tsinghua.edu.cn/"·target="_top">清华大学图书馆</a> | 367 | ········或者在<a·class="link"·href="http://www.lib.tsinghua.edu.cn/"·target="_top">清华大学图书馆</a> |
368 | ········馆藏记录中用"80386"作为关键词所查找到的系统结构方面的书目。</p></div><p> | 368 | ········馆藏记录中用"80386"作为关键词所查找到的系统结构方面的书目。</p></div><p> |
369 | ········在这个任务中,内核将继续工作。在讨论其代码前, | 369 | ········在这个任务中,内核将继续工作。在讨论其代码前, |
370 | ········我将处理器对保护模式必须完成的一系列准备工作一并列出:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>初始化内核的可调整参数,这些参数由引导程序传来</p></li><li·class="listitem"><p>准备GDT(全局描述符表)</p></li><li·class="listitem"><p>准备IDT(中断描述符表)</p></li><li·class="listitem"><p>初始化系统控制台</p></li><li·class="listitem"><p>初始化DDB(内核的点调试器),如果它被编译进内核的话</p></li><li·class="listitem"><p>初始化TSS(任务状态段)</p></li><li·class="listitem"><p>准备LDT(局部描述符表)</p></li><li·class="listitem"><p>建立proc0(0号进程,即内核的进程)的pcb(进程控制块)</p></li></ul></div><a·id="idp59864248"·class="indexterm"></a><p><code·class="function">init386()</code>首先初始化内核的可调整参数, | 370 | ········我将处理器对保护模式必须完成的一系列准备工作一并列出:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>初始化内核的可调整参数,这些参数由引导程序传来</p></li><li·class="listitem"><p>准备GDT(全局描述符表)</p></li><li·class="listitem"><p>准备IDT(中断描述符表)</p></li><li·class="listitem"><p>初始化系统控制台</p></li><li·class="listitem"><p>初始化DDB(内核的点调试器),如果它被编译进内核的话</p></li><li·class="listitem"><p>初始化TSS(任务状态段)</p></li><li·class="listitem"><p>准备LDT(局部描述符表)</p></li><li·class="listitem"><p>建立proc0(0号进程,即内核的进程)的pcb(进程控制块)</p></li></ul></div><a·id="idp59861048"·class="indexterm"></a><p><code·class="function">init386()</code>首先初始化内核的可调整参数, |
371 | ········这些参数由引导程序传来。先设置环境指针(environment·pointer,·envp)调用, | 371 | ········这些参数由引导程序传来。先设置环境指针(environment·pointer,·envp)调用, |
372 | ········再调用<code·class="function">init_param1()</code>。 | 372 | ········再调用<code·class="function">init_param1()</code>。 |
373 | ········envp指针已由loader存放在结构<code·class="literal">bootinfo</code>中:</p><pre·class="programlisting"><code·class="filename">sys/i386/i386/machdep.c:</code> | 373 | ········envp指针已由loader存放在结构<code·class="literal">bootinfo</code>中:</p><pre·class="programlisting"><code·class="filename">sys/i386/i386/machdep.c:</code> |
374 | » » kern_envp·=·(caddr_t)bootinfo.bi_envp·+·KERNBASE; | 374 | » » kern_envp·=·(caddr_t)bootinfo.bi_envp·+·KERNBASE; |
| |
375 | » /*·初始化基本可调整项,如hz等·*/ | 375 | » /*·初始化基本可调整项,如hz等·*/ |
376 | » init_param1();</pre><p><code·class="function">init_param1()</code>定义在 | 376 | » init_param1();</pre><p><code·class="function">init_param1()</code>定义在 |
Offset 382, 15 lines modified | Offset 382, 15 lines modified |
382 | » hz·=·HZ; | 382 | » hz·=·HZ; |
383 | » TUNABLE_INT_FETCH("kern.hz",·&hz);</pre><p>TUNABLE_<typename>_FETCH用来获取环境变量的值:</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/sys/kernel.h</code> | 383 | » TUNABLE_INT_FETCH("kern.hz",·&hz);</pre><p>TUNABLE_<typename>_FETCH用来获取环境变量的值:</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/sys/kernel.h</code> |
384 | #define»TUNABLE_INT_FETCH(path,·var)» getenv_int((path),·(var)) | 384 | #define»TUNABLE_INT_FETCH(path,·var)» getenv_int((path),·(var)) |
385 | </pre><p>Sysctl<code·class="literal">kern.hz</code>是系统时钟频率。同时, | 385 | </pre><p>Sysctl<code·class="literal">kern.hz</code>是系统时钟频率。同时, |
386 | ········这些sysctl项被<code·class="function">init_param1()</code>设定: | 386 | ········这些sysctl项被<code·class="function">init_param1()</code>设定: |
387 | ········<code·class="literal">kern.maxswzone, | 387 | ········<code·class="literal">kern.maxswzone, |
388 | ········kern.maxbcache,·kern.maxtsiz,·kern.dfldsiz,·kern.maxdsiz,·kern.dflssiz, | 388 | ········kern.maxbcache,·kern.maxtsiz,·kern.dfldsiz,·kern.maxdsiz,·kern.dflssiz, |
389 | ········kern.maxssiz,·kern.sgrowsiz</code>。</p><a·id="idp59884472"·class="indexterm"></a><p>然后<code·class="function">init386()</code>·准备全局描述符表 | 389 | ········kern.maxssiz,·kern.sgrowsiz</code>。</p><a·id="idp59888952"·class="indexterm"></a><p>然后<code·class="function">init386()</code>·准备全局描述符表 |
390 | ········(Global·Descriptors·Table,·GDT)。在x86上每个任务都运行在自己的虚拟地址空间里, | 390 | ········(Global·Descriptors·Table,·GDT)。在x86上每个任务都运行在自己的虚拟地址空间里, |
391 | ········这个空间由"段址:偏移量"的数对指定。举个例子,当前将要由处理器执行的指令在 | 391 | ········这个空间由"段址:偏移量"的数对指定。举个例子,当前将要由处理器执行的指令在 |
392 | ········CS:EIP,那么这条指令的线性虚拟地址就是<span·class="quote">“<span·class="quote">代码段虚拟段地址CS</span>”</span>·+·EIP。 | 392 | ········CS:EIP,那么这条指令的线性虚拟地址就是<span·class="quote">“<span·class="quote">代码段虚拟段地址CS</span>”</span>·+·EIP。 |
393 | ········为了简便,段起始于虚拟地址0,终止于界限4G字节。所以,在这个例子中, | 393 | ········为了简便,段起始于虚拟地址0,终止于界限4G字节。所以,在这个例子中, |
394 | ········指令的线性虚拟地址正是EIP的值。段寄存器,如CS、DS等是选择符, | 394 | ········指令的线性虚拟地址正是EIP的值。段寄存器,如CS、DS等是选择符, |
395 | ········即全局描述符表中的索引(更精确的说,索引并非选择符的全部, | 395 | ········即全局描述符表中的索引(更精确的说,索引并非选择符的全部, |
396 | ········而是选择符中的INDEX部分)。</p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">对于80386, | 396 | ········而是选择符中的INDEX部分)。</p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">对于80386, |
Offset 414, 15 lines modified | Offset 414, 15 lines modified |
414 | #define»GPANIC_SEL» 9» /*·会导致全系统异常中止工作的任务状态·*/ | 414 | #define»GPANIC_SEL» 9» /*·会导致全系统异常中止工作的任务状态·*/ |
415 | #define·GBIOSCODE32_SEL»10» /*·BIOS接口(32位代码)·*/ | 415 | #define·GBIOSCODE32_SEL»10» /*·BIOS接口(32位代码)·*/ |
416 | #define·GBIOSCODE16_SEL»11» /*·BIOS接口(16位代码)·*/ | 416 | #define·GBIOSCODE16_SEL»11» /*·BIOS接口(16位代码)·*/ |
417 | #define·GBIOSDATA_SEL» 12» /*·BIOS接口(数据)·*/ | 417 | #define·GBIOSDATA_SEL» 12» /*·BIOS接口(数据)·*/ |
418 | #define·GBIOSUTIL_SEL» 13» /*·BIOS接口(工具)·*/ | 418 | #define·GBIOSUTIL_SEL» 13» /*·BIOS接口(工具)·*/ |
419 | #define·GBIOSARGS_SEL» 14» /*·BIOS接口(自变量,参数)·*/</pre><p>请注意,这些#defines并非选择符本身,而只是选择符中的INDEX域, | 419 | #define·GBIOSARGS_SEL» 14» /*·BIOS接口(自变量,参数)·*/</pre><p>请注意,这些#defines并非选择符本身,而只是选择符中的INDEX域, |
420 | ·······因此它们正是全局描述符表中的索引。 | 420 | ·······因此它们正是全局描述符表中的索引。 |
421 | ·······例如,内核代码的选择符(GCODE_SEL)的值为0x08。</p><a·id="idp59897144"·class="indexterm"></a><p>下一步是初始化中断描述符表(Interrupt·Descriptor·Table,·IDT)。 | 421 | ·······例如,内核代码的选择符(GCODE_SEL)的值为0x08。</p><a·id="idp59898552"·class="indexterm"></a><p>下一步是初始化中断描述符表(Interrupt·Descriptor·Table,·IDT)。 |
422 | ······这张表在发生软件或硬件中断时会被处理器引用。例如,执行系统调用时, | 422 | ······这张表在发生软件或硬件中断时会被处理器引用。例如,执行系统调用时, |
423 | ······用户应用程序提交<code·class="literal">INT·0x80</code>·指令。这是一个软件中断, | 423 | ······用户应用程序提交<code·class="literal">INT·0x80</code>·指令。这是一个软件中断, |
424 | ······处理器用索引值0x80在中断描述符表中查找记录。这个记录指向处理这个中断的例程。 | 424 | ······处理器用索引值0x80在中断描述符表中查找记录。这个记录指向处理这个中断的例程。 |
425 | ······在这个特定情形中,这是内核的系统调用关口。</p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">Intel·80386支持“调用门”,可以使得用户程序只通过一条call指令 | 425 | ······在这个特定情形中,这是内核的系统调用关口。</p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">Intel·80386支持“调用门”,可以使得用户程序只通过一条call指令 |
426 | ······就调用内核中的例程。可是FreeBSD并未采用这种机制, | 426 | ······就调用内核中的例程。可是FreeBSD并未采用这种机制, |
427 | ······也许是因为使用软中断接口可免去动态链接的麻烦吧。另外还有一个附带的好处: | 427 | ······也许是因为使用软中断接口可免去动态链接的麻烦吧。另外还有一个附带的好处: |
428 | ······在仿真Linux时,当遇到FreeBSD内核不支持的而又并非关键性的系统调用时, | 428 | ······在仿真Linux时,当遇到FreeBSD内核不支持的而又并非关键性的系统调用时, |
Offset 433, 15 lines modified | Offset 433, 15 lines modified |
433 | static·struct·gate_descriptor·idt0[NIDT]; | 433 | static·struct·gate_descriptor·idt0[NIDT]; |
434 | struct·gate_descriptor·*idt·=·&idt0[0];» /*·中断描述符表·*/ | 434 | struct·gate_descriptor·*idt·=·&idt0[0];» /*·中断描述符表·*/ |
435 | </pre><p>每个中断都被设置一个合适的中断处理程序。 | 435 | </pre><p>每个中断都被设置一个合适的中断处理程序。 |
436 | ········系统调用关口<code·class="literal">INT·0x80</code>也是如此:</p><pre·class="programlisting"><code·class="filename">sys/i386/i386/machdep.c:</code> | 436 | ········系统调用关口<code·class="literal">INT·0x80</code>也是如此:</p><pre·class="programlisting"><code·class="filename">sys/i386/i386/machdep.c:</code> |
437 | ·» setidt(0x80,·&IDTVEC(int0x80_syscall), | 437 | ·» setidt(0x80,·&IDTVEC(int0x80_syscall), |
438 | » » » SDT_SYS386TGT,·SEL_UPL,·GSEL(GCODE_SEL,·SEL_KPL));</pre><p>所以当一个用户应用程序提交<code·class="literal">INT·0x80</code>指令时, | 438 | » » » SDT_SYS386TGT,·SEL_UPL,·GSEL(GCODE_SEL,·SEL_KPL));</pre><p>所以当一个用户应用程序提交<code·class="literal">INT·0x80</code>指令时, |
439 | ········全系统的控制权会传递给函数<code·class="function">_Xint0x80_syscall</code>, | 439 | ········全系统的控制权会传递给函数<code·class="function">_Xint0x80_syscall</code>, |
440 | ········这个函数在内核代码段中,将被以管理员权限执行。</p><p>然后,控制台和DDB(调试器)被初始化:</p><a·id="idp59925432"·class="indexterm"></a><pre·class="programlisting"><code·class="filename">sys/i386/i386/machdep.c:</code> | 440 | ········这个函数在内核代码段中,将被以管理员权限执行。</p><p>然后,控制台和DDB(调试器)被初始化:</p><a·id="idp59926840"·class="indexterm"></a><pre·class="programlisting"><code·class="filename">sys/i386/i386/machdep.c:</code> |
441 | » cninit(); | 441 | » cninit(); |
442 | /*·以下代码可能因为未定义宏DDB而被跳过·*/ | 442 | /*·以下代码可能因为未定义宏DDB而被跳过·*/ |
443 | #ifdef·DDB | 443 | #ifdef·DDB |
444 | » kdb_init(); | 444 | » kdb_init(); |
445 | » if·(boothowto·&·RB_KDB) | 445 | » if·(boothowto·&·RB_KDB) |
446 | » » Debugger("Boot·flags·requested·debugger"); | 446 | » » Debugger("Boot·flags·requested·debugger"); |
447 | #endif</pre><p>任务状态段(TSS)是另一个x86保护模式中的数据结构。当发生任务切换时, | 447 | #endif</pre><p>任务状态段(TSS)是另一个x86保护模式中的数据结构。当发生任务切换时, |
Offset 459, 24 lines modified | Offset 459, 24 lines modified |
459 | #define·NLDT» » (LBSDICALLS_SEL·+·1) | 459 | #define·NLDT» » (LBSDICALLS_SEL·+·1) |
460 | </pre><p>然后,proc0(0号进程,即内核所处的进程)的进程控制块(Process·Control·Block) | 460 | </pre><p>然后,proc0(0号进程,即内核所处的进程)的进程控制块(Process·Control·Block) |
461 | ·····(<code·class="literal">struct·pcb</code>)结构被初始化。proc0是一个 | 461 | ·····(<code·class="literal">struct·pcb</code>)结构被初始化。proc0是一个 |
462 | ·····<code·class="literal">struct·proc</code>·结构,描述了一个内核进程。 | 462 | ·····<code·class="literal">struct·proc</code>·结构,描述了一个内核进程。 |
463 | ·····内核运行时,该进程总是存在,所以这个结构在内核中被定义为全局变量:</p><pre·class="programlisting"><code·class="filename">sys/kern/kern_init.c:</code> | 463 | ·····内核运行时,该进程总是存在,所以这个结构在内核中被定义为全局变量:</p><pre·class="programlisting"><code·class="filename">sys/kern/kern_init.c:</code> |
464 | ····struct» proc·proc0;</pre><p>结构<code·class="literal">struct·pcb</code>是proc结构的一部分, | 464 | ····struct» proc·proc0;</pre><p>结构<code·class="literal">struct·pcb</code>是proc结构的一部分, |
465 | ·····它定义在<code·class="filename">/usr/include/machine/pcb.h</code>之中, | 465 | ·····它定义在<code·class="filename">/usr/include/machine/pcb.h</code>之中, |
466 | ·····内含针对i386硬件结构专有的信息,如寄存器的值。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp59942840"></a>1.7.2. <code·class="function">mi_startup()</code></h3></div></div></div><p>这个函数用冒泡排序算法,将所有系统初始化对象,然后逐个调用每个对象的入口:</p><pre·class="programlisting"><code·class="filename">sys/kern/init_main.c:</code> | 466 | ·····内含针对i386硬件结构专有的信息,如寄存器的值。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp59942200"></a>1.7.2. <code·class="function">mi_startup()</code></h3></div></div></div><p>这个函数用冒泡排序算法,将所有系统初始化对象,然后逐个调用每个对象的入口:</p><pre·class="programlisting"><code·class="filename">sys/kern/init_main.c:</code> |
467 | » for·(sipp·=·sysinit;·*sipp;·sipp++)·{ | 467 | » for·(sipp·=·sysinit;·*sipp;·sipp++)·{ |
| |
468 | » » /*·...·省略·...·*/ | 468 | » » /*·...·省略·...·*/ |
| |
469 | » » /*·调用函数·*/ | 469 | » » /*·调用函数·*/ |
470 | » » (*((*sipp)->func))((*sipp)->udata); | 470 | » » (*((*sipp)->func))((*sipp)->udata); |
471 | » » /*·...·省略·...·*/ | 471 | » » /*·...·省略·...·*/ |
472 | » }</pre><p>尽管sysinit框架已经在《FreeBSD开发者手册》中有所描述, | 472 | » }</pre><p>尽管sysinit框架已经在《FreeBSD开发者手册》中有所描述, |
473 | ······我还是在这里讨论一下其内部原理。</p><a·id="idp59963448"·class="indexterm"></a><p>每个系统初始化对象(sysinit对象)通过调用宏建立。 | 473 | ······我还是在这里讨论一下其内部原理。</p><a·id="idp59960760"·class="indexterm"></a><p>每个系统初始化对象(sysinit对象)通过调用宏建立。 |
474 | ······让我们以<code·class="literal">announce</code>·sysinit对象为例。 | 474 | ······让我们以<code·class="literal">announce</code>·sysinit对象为例。 |
475 | ······这个对象打印版权信息:</p><pre·class="programlisting"><code·class="filename">sys/kern/init_main.c:</code> | 475 | ······这个对象打印版权信息:</p><pre·class="programlisting"><code·class="filename">sys/kern/init_main.c:</code> |
476 | static·void | 476 | static·void |
477 | print_caddr_t(void·*data·__unused) | 477 | print_caddr_t(void·*data·__unused) |
478 | { | 478 | { |
479 | » printf("%s",·(char·*)data); | 479 | » printf("%s",·(char·*)data); |
480 | } | 480 | } |
Offset 582, 31 lines modified | Offset 582, 31 lines modified |
582 | ····先尝试<code·class="filename">/sbin/init</code>,然后是<code·class="filename">/sbin/oinit</code>, | 582 | ····先尝试<code·class="filename">/sbin/init</code>,然后是<code·class="filename">/sbin/oinit</code>, |
583 | ····<code·class="filename">/sbin/init.bak</code>,最后是<code·class="filename">/stand/sysinstall</code>:</p><pre·class="programlisting"><code·class="filename">sys/kern/init_main.c:</code> | 583 | ····<code·class="filename">/sbin/init.bak</code>,最后是<code·class="filename">/stand/sysinstall</code>:</p><pre·class="programlisting"><code·class="filename">sys/kern/init_main.c:</code> |
584 | static·char·init_path[MAXPATHLEN]·= | 584 | static·char·init_path[MAXPATHLEN]·= |
585 | #ifdef» INIT_PATH | 585 | #ifdef» INIT_PATH |
586 | ····__XSTRING(INIT_PATH); | 586 | ····__XSTRING(INIT_PATH); |
587 | #else | 587 | #else |
588 | ····"/sbin/init:/sbin/oinit:/sbin/init.bak:/stand/sysinstall"; | 588 | ····"/sbin/init:/sbin/oinit:/sbin/init.bak:/stand/sysinstall"; |
589 | #endif</pre></div></div><div·class="footnotes"><br·/><hr·class="footnote-hr"·/><div·id="ftn.idp59541816"·class="footnote"><p><a·href="#idp59541816"·class="para"><sup·class="para">[1]·</sup></a>有些工具如<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=disklabel&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">disklabel</span>(8)</span></a> | 589 | #endif</pre></div></div><div·class="footnotes"><br·/><hr·class="footnote-hr"·/><div·id="ftn.idp59543224"·class="footnote"><p><a·href="#idp59543224"·class="para"><sup·class="para">[1]·</sup></a>有些工具如<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=disklabel&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">disklabel</span>(8)</span></a> |
590 | ······会使用这一区域存储信息,主要是在第二扇区里。</p></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="locking"></a>第 2 章 内核中的锁</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#locking-mutexes">2.1.·Mutex</a></span></dt><dt><span·class="sect1"><a·href="#locking-sx">2.2.·共享互斥锁</a></span></dt><dt><span·class="sect1"><a·href="#locking-atomic">2.3.·原子保护变量</a></span></dt></dl></div><a·id="idp60073016"·class="indexterm"></a><p><span·class="emphasis"><em>这一章由·FreeBSD·SMP·Next·Generation·Project·维护。 | 590 | ······会使用这一区域存储信息,主要是在第二扇区里。</p></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="locking"></a>第 2 章 内核中的锁</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#locking-mutexes">2.1.·Mutex</a></span></dt><dt><span·class="sect1"><a·href="#locking-sx">2.2.·共享互斥锁</a></span></dt><dt><span·class="sect1"><a·href="#locking-atomic">2.3.·原子保护变量</a></span></dt></dl></div><a·id="idp60073144"·class="indexterm"></a><p><span·class="emphasis"><em>这一章由·FreeBSD·SMP·Next·Generation·Project·维护。 |
591 | ····请将评论和建议发送给<a·class="link"·href="http://lists.FreeBSD.org/mailman/listinfo/freebsd-smp"·target="_top">FreeBSD·对称多处理·(SMP)·邮件列表</a>.</em></span></p><a·id="idp60077496"·class="indexterm"></a><a·id="idp60079160"·class="indexterm"></a><a·id="idp60080824"·class="indexterm"></a><a·id="idp60082488"·class="indexterm"></a><a·id="idp60084152"·class="indexterm"></a><p>这篇文档提纲挈领的讲述了在FreeBSD内核中的锁,这些锁使得有效的多处理成为可能。 | 591 | ····请将评论和建议发送给<a·class="link"·href="http://lists.FreeBSD.org/mailman/listinfo/freebsd-smp"·target="_top">FreeBSD·对称多处理·(SMP)·邮件列表</a>.</em></span></p><a·id="idp60076600"·class="indexterm"></a><a·id="idp60077496"·class="indexterm"></a><a·id="idp60079672"·class="indexterm"></a><a·id="idp60081336"·class="indexterm"></a><a·id="idp60083000"·class="indexterm"></a><p>这篇文档提纲挈领的讲述了在FreeBSD内核中的锁,这些锁使得有效的多处理成为可能。 |
592 | ···锁可以用几种方式获得。数据结构可以用mutex或<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=lockmgr&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">lockmgr</span>(9)</span></a>保护。 | 592 | ···锁可以用几种方式获得。数据结构可以用mutex或<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=lockmgr&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">lockmgr</span>(9)</span></a>保护。 |
593 | ···对于为数不多的若干个变量,假如总是使用原子操作访问它们,这些变量就可以得到保护。 | 593 | ···对于为数不多的若干个变量,假如总是使用原子操作访问它们,这些变量就可以得到保护。 |
594 | ···</p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">仅读本章内容,还不足以找出<span·class="quote">“<span·class="quote">mutex</span>”</span> | 594 | ···</p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">仅读本章内容,还不足以找出<span·class="quote">“<span·class="quote">mutex</span>”</span> |
595 | ···和<span·class="quote">“<span·class="quote">共享互斥锁</span>”</span>的区别。似乎它们的功能有重叠之处, | 595 | ···和<span·class="quote">“<span·class="quote">共享互斥锁</span>”</span>的区别。似乎它们的功能有重叠之处, |
596 | ···前者比后者的功能选项更多。它们似乎都是<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=lockmgr&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">lockmgr</span>(9)</span></a>的子集。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="locking-mutexes"></a>2.1. Mutex</h2></div></div></div><p>Mutex就是一种用来解决共享/排它矛盾的锁。 | 596 | ···前者比后者的功能选项更多。它们似乎都是<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=lockmgr&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">lockmgr</span>(9)</span></a>的子集。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="locking-mutexes"></a>2.1. Mutex</h2></div></div></div><p>Mutex就是一种用来解决共享/排它矛盾的锁。 |
597 | ·····一个mutex在一个时刻只可以被一个实体拥有。如果另一个实体要获得已经被拥有的mutex, | 597 | ·····一个mutex在一个时刻只可以被一个实体拥有。如果另一个实体要获得已经被拥有的mutex, |
598 | ·····就会进入等待,直到这个mutex被释放。在FreeBSD内核中,mutex被进程所拥有。</p><p>Mutex可以被递归的索要,但是mutex一般只被一个实体拥有较短的一段时间, | 598 | ·····就会进入等待,直到这个mutex被释放。在FreeBSD内核中,mutex被进程所拥有。</p><p>Mutex可以被递归的索要,但是mutex一般只被一个实体拥有较短的一段时间, |
599 | ·····因此一个实体不能在持有mutex时睡眠。如果你需要在持有mutex时睡眠, | 599 | ·····因此一个实体不能在持有mutex时睡眠。如果你需要在持有mutex时睡眠, |
600 | ·····可使用一个·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=lockmgr&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">lockmgr</span>(9)</span></a>·的锁。</p><p>每个mutex有几个令人感兴趣的属性:</p><div·class="variablelist"><dl·class="variablelist"><dt><span·class="term">变量名</span></dt><dd><p>在内核源代码中<span·class="type">struct·mtx</span>变量的名字</p></dd><dt><span·class="term">逻辑名</span></dt><dd><p>由函数<code·class="function">mtx_init</code>指派的mutex的名字。 | 600 | ·····可使用一个·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=lockmgr&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">lockmgr</span>(9)</span></a>·的锁。</p><p>每个mutex有几个令人感兴趣的属性:</p><div·class="variablelist"><dl·class="variablelist"><dt><span·class="term">变量名</span></dt><dd><p>在内核源代码中<span·class="type">struct·mtx</span>变量的名字</p></dd><dt><span·class="term">逻辑名</span></dt><dd><p>由函数<code·class="function">mtx_init</code>指派的mutex的名字。 |
601 | ············这个名字显示在KTR跟踪消息和witness出错与警告信息里。 | 601 | ············这个名字显示在KTR跟踪消息和witness出错与警告信息里。 |
602 | ············这个名字还用于区分标识在witness代码中的各个mutex</p></dd><dt><span·class="term">类型</span></dt><dd><p>Mutex的类型,用标志<code·class="constant">MTX_*</code>表示。 | 602 | ············这个名字还用于区分标识在witness代码中的各个mutex</p></dd><dt><span·class="term">类型</span></dt><dd><p>Mutex的类型,用标志<code·class="constant">MTX_*</code>表示。 |
603 | ············每个标志的意义在<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=mutex&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">mutex</span>(9)</span></a>有所描述。</p><div·class="variablelist"><dl·class="variablelist"><dt><span·class="term"><code·class="constant">MTX_DEF</code></span></dt><dd><p>一个睡眠mutex</p></dd><dt><span·class="term"><code·class="constant">MTX_SPIN</code></span></dt><dd><p>一个循环mutex</p></dd><dt><span·class="term"><code·class="constant">MTX_RECURSE</code></span></dt><dd><p>这个mutex允许递归</p></dd></dl></div></dd><dt><span·class="term">保护对象</span></dt><dd><p>这个入口所要保护的数据结构列表或数据结构成员列表。 | 603 | ············每个标志的意义在<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=mutex&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">mutex</span>(9)</span></a>有所描述。</p><div·class="variablelist"><dl·class="variablelist"><dt><span·class="term"><code·class="constant">MTX_DEF</code></span></dt><dd><p>一个睡眠mutex</p></dd><dt><span·class="term"><code·class="constant">MTX_SPIN</code></span></dt><dd><p>一个循环mutex</p></dd><dt><span·class="term"><code·class="constant">MTX_RECURSE</code></span></dt><dd><p>这个mutex允许递归</p></dd></dl></div></dd><dt><span·class="term">保护对象</span></dt><dd><p>这个入口所要保护的数据结构列表或数据结构成员列表。 |
604 | » ····对于数据结构成员,将按照 | 604 | » ····对于数据结构成员,将按照 |
605 | » ····<code·class="varname">结构名</code>.<code·class="varname">成员名</code>的形式命名。</p></dd><dt><span·class="term">依赖函数</span></dt><dd><p>仅当mutex被持有时才可以被调用的函数</p></dd></dl></div><div·class="table"><a·id="idp60172856"></a><div·class="table-title">表 2.1. Mutex列表</div><div·class="table-contents"><a·id="idp60176312"·class="indexterm"></a><a·id="idp60178744"·class="indexterm"></a><a·id="idp60181176"·class="indexterm"></a><a·id="idp60183224"·class="indexterm"></a><table·summary="Mutex列表"·width="100%"·border="1"><colgroup><col·/><col·/><col·/><col·/><col·/></colgroup><thead><tr><th>变量名</th><th>逻辑名</th><th>类型</th><th>保护对象</th><th>依赖函数</th></tr></thead><tbody><tr><td>sched_lock</td><td><span·class="quote">“<span·class="quote">sched·lock</span>”</span>(调度器锁)</td><td> | 605 | » ····<code·class="varname">结构名</code>.<code·class="varname">成员名</code>的形式命名。</p></dd><dt><span·class="term">依赖函数</span></dt><dd><p>仅当mutex被持有时才可以被调用的函数</p></dd></dl></div><div·class="table"><a·id="idp60163768"></a><div·class="table-title">表 2.1. Mutex列表</div><div·class="table-contents"><a·id="idp60167224"·class="indexterm"></a><a·id="idp60169016"·class="indexterm"></a><a·id="idp60172216"·class="indexterm"></a><a·id="idp60174648"·class="indexterm"></a><table·summary="Mutex列表"·width="100%"·border="1"><colgroup><col·/><col·/><col·/><col·/><col·/></colgroup><thead><tr><th>变量名</th><th>逻辑名</th><th>类型</th><th>保护对象</th><th>依赖函数</th></tr></thead><tbody><tr><td>sched_lock</td><td><span·class="quote">“<span·class="quote">sched·lock</span>”</span>(调度器锁)</td><td> |
606 | » ······<code·class="constant">MTX_SPIN</code>·| | 606 | » ······<code·class="constant">MTX_SPIN</code>·| |
607 | » ······<code·class="constant">MTX_RECURSE</code> | 607 | » ······<code·class="constant">MTX_RECURSE</code> |
608 | » ····</td><td> | 608 | » ····</td><td> |
609 | » ······<code·class="varname">_gmonparam</code>, | 609 | » ······<code·class="varname">_gmonparam</code>, |
610 | » ······<code·class="varname">cnt.v_swtch</code>, | 610 | » ······<code·class="varname">cnt.v_swtch</code>, |
611 | » ······<code·class="varname">cp_time</code>, | 611 | » ······<code·class="varname">cp_time</code>, |
612 | » ······<code·class="varname">curpriority</code>, | 612 | » ······<code·class="varname">curpriority</code>, |
Offset 691, 50 lines modified | Offset 691, 50 lines modified |
691 | » ······<code·class="varname">nextsoftcheck</code>, | 691 | » ······<code·class="varname">nextsoftcheck</code>, |
692 | » ······<code·class="varname">proc</code>.<code·class="varname">p_itcallout</code>, | 692 | » ······<code·class="varname">proc</code>.<code·class="varname">p_itcallout</code>, |
693 | » ······<code·class="varname">proc</code>.<code·class="varname">p_slpcallout</code>, | 693 | » ······<code·class="varname">proc</code>.<code·class="varname">p_slpcallout</code>, |
694 | » ······<code·class="varname">softticks</code>, | 694 | » ······<code·class="varname">softticks</code>, |
695 | » ······<code·class="varname">ticks</code> | 695 | » ······<code·class="varname">ticks</code> |
696 | » ····</td><td> | 696 | » ····</td><td> |
697 | » ····</td></tr></tbody></table></div></div><br·class="table-break"·/></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="locking-sx"></a>2.2. 共享互斥锁</h2></div></div></div><p>这些锁提供基本的读/写类型的功能,可以被一个正在睡眠的进程持有。 | 697 | » ····</td></tr></tbody></table></div></div><br·class="table-break"·/></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="locking-sx"></a>2.2. 共享互斥锁</h2></div></div></div><p>这些锁提供基本的读/写类型的功能,可以被一个正在睡眠的进程持有。 |
698 | ······现在它们被统一到<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=lockmgr&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">lockmgr</span>(9)</span></a>之中。</p><a·id="idp60517432"·class="indexterm"></a><div·class="table"><a·id="idp60519224"></a><div·class="table-title">表 2.2. 共享互斥锁列表</div><div·class="table-contents"><a·id="idp60520760"·class="indexterm"></a><a·id="idp60522552"·class="indexterm"></a><table·summary="共享互斥锁列表"·border="1"><colgroup><col·/><col·/></colgroup><thead><tr><th>变量名</th><th>保护对象</th></tr></thead><tbody><tr><td><code·class="varname">allproc_lock</code></td><td> | 698 | ······现在它们被统一到<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=lockmgr&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">lockmgr</span>(9)</span></a>之中。</p><a·id="idp60516920"·class="indexterm"></a><div·class="table"><a·id="idp60518968"></a><div·class="table-title">表 2.2. 共享互斥锁列表</div><div·class="table-contents"><a·id="idp60519992"·class="indexterm"></a><a·id="idp60521784"·class="indexterm"></a><table·summary="共享互斥锁列表"·border="1"><colgroup><col·/><col·/></colgroup><thead><tr><th>变量名</th><th>保护对象</th></tr></thead><tbody><tr><td><code·class="varname">allproc_lock</code></td><td> |
699 | » ······<code·class="varname">allproc</code> | 699 | » ······<code·class="varname">allproc</code> |
700 | » ······<code·class="varname">zombproc</code> | 700 | » ······<code·class="varname">zombproc</code> |
701 | » ······<code·class="varname">pidhashtbl</code> | 701 | » ······<code·class="varname">pidhashtbl</code> |
702 | » ······<code·class="varname">proc</code>.<code·class="varname">p_list</code> | 702 | » ······<code·class="varname">proc</code>.<code·class="varname">p_list</code> |
703 | » ······<code·class="varname">proc</code>.<code·class="varname">p_hash</code> | 703 | » ······<code·class="varname">proc</code>.<code·class="varname">p_hash</code> |
704 | » ······<code·class="varname">nextpid</code> | 704 | » ······<code·class="varname">nextpid</code> |
705 | » ····</td></tr><tr><td><code·class="varname">proctree_lock</code></td><td> | 705 | » ····</td></tr><tr><td><code·class="varname">proctree_lock</code></td><td> |
706 | » ······<code·class="varname">proc</code>.<code·class="varname">p_children</code> | 706 | » ······<code·class="varname">proc</code>.<code·class="varname">p_children</code> |
707 | » ······<code·class="varname">proc</code>.<code·class="varname">p_sibling</code> | 707 | » ······<code·class="varname">proc</code>.<code·class="varname">p_sibling</code> |
708 | » ····</td></tr></tbody></table></div></div><br·class="table-break"·/></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="locking-atomic"></a>2.3. 原子保护变量</h2></div></div></div><a·id="idp60571448"·class="indexterm"></a><p>原子保护变量并非由一个显在的锁保护的特殊变量,而是: | 708 | » ····</td></tr></tbody></table></div></div><br·class="table-break"·/></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="locking-atomic"></a>2.3. 原子保护变量</h2></div></div></div><a·id="idp60570424"·class="indexterm"></a><p>原子保护变量并非由一个显在的锁保护的特殊变量,而是: |
709 | ······对这些变量的所有数据访问都要使用特殊的原子操作(<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=atomic&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">atomic</span>(9)</span></a>)。 | 709 | ······对这些变量的所有数据访问都要使用特殊的原子操作(<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=atomic&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">atomic</span>(9)</span></a>)。 |
710 | ······尽管其它的基本同步机制(例如mutex)就是用原子保护变量实现的, | 710 | ······尽管其它的基本同步机制(例如mutex)就是用原子保护变量实现的, |
711 | ······但是很少有变量直接使用这种处理方式。</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><code·class="varname">mtx</code>.<code·class="varname">mtx_lock</code></p></li></ul></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="kernel-objects"></a>第 3 章 内核对象</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#kernel-objects-term">3.1.·术语</a></span></dt><dt><span·class="sect1"><a·href="#kernel-objects-operation">3.2.·Kobj的工作流程</a></span></dt><dt><span·class="sect1"><a·href="#kernel-objects-using">3.3.·使用Kobj</a></span></dt></dl></div><a·id="idp60588472"·class="indexterm"></a><a·id="idp60589240"·class="indexterm"></a><a·id="idp60590136"·class="indexterm"></a><p>内核对象,也就是<em·class="firstterm">Kobj</em>,·✂ | 711 | ······但是很少有变量直接使用这种处理方式。</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><code·class="varname">mtx</code>.<code·class="varname">mtx_lock</code></p></li></ul></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="kernel-objects"></a>第 3 章 内核对象</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#kernel-objects-term">3.1.·术语</a></span></dt><dt><span·class="sect1"><a·href="#kernel-objects-operation">3.2.·Kobj的工作流程</a></span></dt><dt><span·class="sect1"><a·href="#kernel-objects-using">3.3.·使用Kobj</a></span></dt></dl></div><a·id="idp60587576"·class="indexterm"></a><a·id="idp60588984"·class="indexterm"></a><a·id="idp60589880"·class="indexterm"></a><p>内核对象,也就是<em·class="firstterm">Kobj</em>,·✂ |
712 | ····的C语言编程方式。被操作的数据也承载操作它的方法。 | 712 | ····的C语言编程方式。被操作的数据也承载操作它的方法。 |
713 | ····这使得在不破坏二进制兼容性的前提下,某一个接口能够增/减相应的操作。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="kernel-objects-term"></a>3.1. 术语</h2></div></div></div><a·id="idp60595896"·class="indexterm"></a><a·id="idp60597560"·class="indexterm"></a><a·id="idp60598968"·class="indexterm"></a><a·id="idp60604216"·class="indexterm"></a><div·class="variablelist"><dl·class="variablelist"><dt><span·class="term">对象</span></dt><dd><p>数据集合-数据结构-数据分配的集合</p></dd><dt><span·class="term">方法</span></dt><dd><p>某一种操作──函数</p></dd><dt><span·class="term">类</span></dt><dd><p>一种或多种方法</p></dd><dt><span·class="term">接口</span></dt><dd><p>一种或多种方法的一个标准集合</p></dd></dl></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="kernel-objects-operation"></a>3.2. Kobj的工作流程</h2></div></div></div><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.·✂ | 713 | ····这使得在不破坏二进制兼容性的前提下,某一个接口能够增/减相应的操作。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="kernel-objects-term"></a>3.1. 术语</h2></div></div></div><a·id="idp60595640"·class="indexterm"></a><a·id="idp60597304"·class="indexterm"></a><a·id="idp60598456"·class="indexterm"></a><a·id="idp60599224"·class="indexterm"></a><div·class="variablelist"><dl·class="variablelist"><dt><span·class="term">对象</span></dt><dd><p>数据集合-数据结构-数据分配的集合</p></dd><dt><span·class="term">方法</span></dt><dd><p>某一种操作──函数</p></dd><dt><span·class="term">类</span></dt><dd><p>一种或多种方法</p></dd><dt><span·class="term">接口</span></dt><dd><p>一种或多种方法的一个标准集合</p></dd></dl></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="kernel-objects-operation"></a>3.2. Kobj的工作流程</h2></div></div></div><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.·✂ |
714 | » 请参考我在括号中的注释阅读。</p></div><p>Kobj工作时,产生方法的描述。每个描述有一个唯一的标识和一个缺省函数。 | 714 | » 请参考我在括号中的注释阅读。</p></div><p>Kobj工作时,产生方法的描述。每个描述有一个唯一的标识和一个缺省函数。 |
715 | ······某个描述的地址被用来在一个类的方法表里唯一的标识方法。</p><p>构建一个类,就是要建立一张方法表,并将这张表关联到一个或多个函数(方法); | 715 | ······某个描述的地址被用来在一个类的方法表里唯一的标识方法。</p><p>构建一个类,就是要建立一张方法表,并将这张表关联到一个或多个函数(方法); |
716 | ······这些函数(方法)都带有方法描述。使用前,类要被编译。编译时要为这个类分配一些缓存。 | 716 | ······这些函数(方法)都带有方法描述。使用前,类要被编译。编译时要为这个类分配一些缓存。 |
717 | ······在方法表中的每个方法描述都会被指派一个唯一的标识, | 717 | ······在方法表中的每个方法描述都会被指派一个唯一的标识, |
718 | ······除非已经被其它引用它的类在编译时指派了标识。对于每个将要被使用的方法, | 718 | ······除非已经被其它引用它的类在编译时指派了标识。对于每个将要被使用的方法, |
719 | ······都会由脚本生成一个函数(方法查找函数),以解析外来参数, | 719 | ······都会由脚本生成一个函数(方法查找函数),以解析外来参数, |
720 | ······并在被查询时给出方法描述的地址。被生成的函数(方法查找函数) | 720 | ······并在被查询时给出方法描述的地址。被生成的函数(方法查找函数) |
721 | ······凭着那个方法描述的唯一标识按Hash的方法查找对象的类的缓存。 | 721 | ······凭着那个方法描述的唯一标识按Hash的方法查找对象的类的缓存。 |
722 | ······如果这个方法不在缓存中,函数会查找使用类的方法表。如果这个方法被找到了, | 722 | ······如果这个方法不在缓存中,函数会查找使用类的方法表。如果这个方法被找到了, |
723 | ······类里的相关函数(也就是某个方法的实现代码)就会被使用。 | 723 | ······类里的相关函数(也就是某个方法的实现代码)就会被使用。 |
724 | ······否则,这个方法描述的缺省函数将被使用。</p><p>这些过程可被表示如下:</p><pre·class="programlisting">对象->缓存<->类</pre></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="kernel-objects-using"></a>3.3. 使用Kobj</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60648632"></a>3.3.1. 结构</h3></div></div></div><pre·class="programlisting">struct·kobj_method</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60653240"></a>3.3.2. 函数</h3></div></div></div><pre·class="programlisting">void·kobj_class_compile(kobj_class_t·cls); | 724 | ······否则,这个方法描述的缺省函数将被使用。</p><p>这些过程可被表示如下:</p><pre·class="programlisting">对象->缓存<->类</pre></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="kernel-objects-using"></a>3.3. 使用Kobj</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60647608"></a>3.3.1. 结构</h3></div></div></div><pre·class="programlisting">struct·kobj_method</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60652216"></a>3.3.2. 函数</h3></div></div></div><pre·class="programlisting">void·kobj_class_compile(kobj_class_t·cls); |
725 | void·kobj_class_compile_static(kobj_class_t·cls,·kobj_ops_t·ops); | 725 | void·kobj_class_compile_static(kobj_class_t·cls,·kobj_ops_t·ops); |
726 | void·kobj_class_free(kobj_class_t·cls); | 726 | void·kobj_class_free(kobj_class_t·cls); |
727 | kobj_t·kobj_create(kobj_class_t·cls,·struct·malloc_type·*mtype,·int·mflags); | 727 | kobj_t·kobj_create(kobj_class_t·cls,·struct·malloc_type·*mtype,·int·mflags); |
728 | void·kobj_init(kobj_t·obj,·kobj_class_t·cls); | 728 | void·kobj_init(kobj_t·obj,·kobj_class_t·cls); |
729 | void·kobj_delete(kobj_t·obj,·struct·malloc_type·*mtype);</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60657336"></a>3.3.3. 宏</h3></div></div></div><pre·class="programlisting">KOBJ_CLASS_FIELDS | 729 | void·kobj_delete(kobj_t·obj,·struct·malloc_type·*mtype);</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60656824"></a>3.3.3. 宏</h3></div></div></div><pre·class="programlisting">KOBJ_CLASS_FIELDS |
730 | KOBJ_FIELDS | 730 | KOBJ_FIELDS |
731 | DEFINE_CLASS(name,·methods,·size) | 731 | DEFINE_CLASS(name,·methods,·size) |
732 | KOBJMETHOD(NAME,·FUNC)</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60660152"></a>3.3.4. 头文件</h3></div></div></div><pre·class="programlisting"><sys/param.h> | 732 | KOBJMETHOD(NAME,·FUNC)</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60659384"></a>3.3.4. 头文件</h3></div></div></div><pre·class="programlisting"><sys/param.h> |
733 | <sys/kobj.h></pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60663224"></a>3.3.5. 建立一个接口的模板</h3></div></div></div><a·id="idp60664632"·class="indexterm"></a><p>使用Kobj的第一步是建立一个接口。建立接口包括建立模板的工作。 | 733 | <sys/kobj.h></pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60662712"></a>3.3.5. 建立一个接口的模板</h3></div></div></div><a·id="idp60664120"·class="indexterm"></a><p>使用Kobj的第一步是建立一个接口。建立接口包括建立模板的工作。 |
734 | ·······建立模板可用脚本<code·class="filename">src/sys/kern/makeobjops.pl</code>完成, | 734 | ·······建立模板可用脚本<code·class="filename">src/sys/kern/makeobjops.pl</code>完成, |
735 | ·······它会产生申明方法的头文件和代码,脚本还会生成方法查找函数。</p><p>在这个模板中如下关键词会被使用: | 735 | ·······它会产生申明方法的头文件和代码,脚本还会生成方法查找函数。</p><p>在这个模板中如下关键词会被使用: |
736 | ········<code·class="literal">#include</code>,·<code·class="literal">INTERFACE</code>, | 736 | ········<code·class="literal">#include</code>,·<code·class="literal">INTERFACE</code>, |
737 | ········<code·class="literal">CODE</code>,·<code·class="literal">METHOD</code>, | 737 | ········<code·class="literal">CODE</code>,·<code·class="literal">METHOD</code>, |
738 | ········<code·class="literal">STATICMETHOD</code>,·和 | 738 | ········<code·class="literal">STATICMETHOD</code>,·和 |
739 | ········<code·class="literal">DEFAULT</code>.</p><p><code·class="literal">#include</code>语句的整行内容将被一字不差的 | 739 | ········<code·class="literal">DEFAULT</code>.</p><p><code·class="literal">#include</code>语句的整行内容将被一字不差的 |
740 | ········复制到被生成的代码文件的头部。</p><p>例如:</p><pre·class="programlisting">#include·<sys/foo.h></pre><p>关键词<code·class="literal">INTERFACE</code>用来定义接口名。 | 740 | ········复制到被生成的代码文件的头部。</p><p>例如:</p><pre·class="programlisting">#include·<sys/foo.h></pre><p>关键词<code·class="literal">INTERFACE</code>用来定义接口名。 |
Offset 766, 43 lines modified | Offset 766, 43 lines modified |
766 | ········而<code·class="literal">STATICMETHOD</code>定义的对象可以不受这个限制: | 766 | ········而<code·class="literal">STATICMETHOD</code>定义的对象可以不受这个限制: |
767 | ········这样描述出的方法,其操作的数据不由这个类的某个对象实例给出, | 767 | ········这样描述出的方法,其操作的数据不由这个类的某个对象实例给出, |
768 | ········而是全都由调用这个方法时的操作数(译者注:即参数)给出。 | 768 | ········而是全都由调用这个方法时的操作数(译者注:即参数)给出。 |
769 | ········这也对于在某个类的方法表之外调用这个方法有用。 | 769 | ········这也对于在某个类的方法表之外调用这个方法有用。 |
770 | » </p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">这一段的语言与原文相比调整很大。 | 770 | » </p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">这一段的语言与原文相比调整很大。 |
771 | ········静态方法是不依赖于对象实例的方法。 | 771 | ········静态方法是不依赖于对象实例的方法。 |
772 | ········参看C++类中的“静态函数”的概念。</p></div><p>其它完整的例子:</p><pre·class="programlisting">src/sys/kern/bus_if.m | 772 | ········参看C++类中的“静态函数”的概念。</p></div><p>其它完整的例子:</p><pre·class="programlisting">src/sys/kern/bus_if.m |
773 | src/sys/kern/device_if.m</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60725048"></a>3.3.6. 建立一个类</h3></div></div></div><a·id="idp60738872"·class="indexterm"></a><p>使用Kobj的第二步是建立一个类。一个类的组有名字、方法表; | 773 | src/sys/kern/device_if.m</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60732728"></a>3.3.6. 建立一个类</h3></div></div></div><a·id="idp60733880"·class="indexterm"></a><p>使用Kobj的第二步是建立一个类。一个类的组有名字、方法表; |
774 | ········假如使用了Kobj的“对象管理工具”(Object·Handling·Facilities), | 774 | ········假如使用了Kobj的“对象管理工具”(Object·Handling·Facilities), |
775 | ········类中还包含对象的大小。建立类时使用宏<code·class="function">DEFINE_CLASS()</code>。 | 775 | ········类中还包含对象的大小。建立类时使用宏<code·class="function">DEFINE_CLASS()</code>。 |
776 | ········建立方法表时,须建立一个kobj_method_t数组,用NULL项结尾。 | 776 | ········建立方法表时,须建立一个kobj_method_t数组,用NULL项结尾。 |
777 | ········每个非NULL项可用宏<code·class="function">KOBJMETHOD()</code>建立。</p><p>例如:</p><pre·class="programlisting">DEFINE_CLASS(fooclass,·foomethods,·sizeof(struct·foodata)); | 777 | ········每个非NULL项可用宏<code·class="function">KOBJMETHOD()</code>建立。</p><p>例如:</p><pre·class="programlisting">DEFINE_CLASS(fooclass,·foomethods,·sizeof(struct·foodata)); |
| |
778 | kobj_method_t·foomethods[]·=·{ | 778 | kobj_method_t·foomethods[]·=·{ |
779 | » KOBJMETHOD(bar_doo,·foo_doo), | 779 | » KOBJMETHOD(bar_doo,·foo_doo), |
780 | » KOBJMETHOD(bar_foo,·foo_foo), | 780 | » KOBJMETHOD(bar_foo,·foo_foo), |
781 | » {·NULL,·NULL} | 781 | » {·NULL,·NULL} |
782 | };</pre><p>类须被<span·class="quote">“<span·class="quote">编译</span>”</span>。根据该类被初始化时系统的状态, | 782 | };</pre><p>类须被<span·class="quote">“<span·class="quote">编译</span>”</span>。根据该类被初始化时系统的状态, |
783 | ········将要用到一个静态分配的缓存和<span·class="quote">“<span·class="quote">操作数表</span>”</span>(ops·table, | 783 | ········将要用到一个静态分配的缓存和<span·class="quote">“<span·class="quote">操作数表</span>”</span>(ops·table, |
784 | ········译者注:即<span·class="quote">“<span·class="quote">参数表</span>”</span>)。这些操作可通过声明一个结构体 | 784 | ········译者注:即<span·class="quote">“<span·class="quote">参数表</span>”</span>)。这些操作可通过声明一个结构体 |
785 | ········<code·class="varname">struct·kobj_ops</code>并使用 | 785 | ········<code·class="varname">struct·kobj_ops</code>并使用 |
786 | ········<code·class="function">kobj_class_compile_static()</code>, | 786 | ········<code·class="function">kobj_class_compile_static()</code>, |
787 | ········或是只使用<code·class="function">kobj_class_compile()</code>来完成。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60753208"></a>3.3.7. 建立一个对象</h3></div></div></div><a·id="idp60755256"·class="indexterm"></a><p>使用Kobj的第三步是定义对象。Kobj对象建立程序假定Kobj | 787 | ········或是只使用<code·class="function">kobj_class_compile()</code>来完成。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60748600"></a>3.3.7. 建立一个对象</h3></div></div></div><a·id="idp60750136"·class="indexterm"></a><p>使用Kobj的第三步是定义对象。Kobj对象建立程序假定Kobj |
788 | ········专有数据在一个对象的头部。如果不是如此,应当先自行分配对象, | 788 | ········专有数据在一个对象的头部。如果不是如此,应当先自行分配对象, |
789 | ········再使用<code·class="function">kobj_init()</code>初始化对象中的Kobj专有数据; | 789 | ········再使用<code·class="function">kobj_init()</code>初始化对象中的Kobj专有数据; |
790 | ········其实可以使用<code·class="function">kobj_create()</code>分配对象, | 790 | ········其实可以使用<code·class="function">kobj_create()</code>分配对象, |
791 | ········并自动初始化对象中的Kobj专有内容。<code·class="function">kobj_init()</code> | 791 | ········并自动初始化对象中的Kobj专有内容。<code·class="function">kobj_init()</code> |
792 | ········也可以用来改变一个对象所使用的类。</p><p>将Kobj的数据集成到对象中要使用宏KOBJ_FIELDS。</p><p>例如</p><pre·class="programlisting">struct·foo_data·{ | 792 | ········也可以用来改变一个对象所使用的类。</p><p>将Kobj的数据集成到对象中要使用宏KOBJ_FIELDS。</p><p>例如</p><pre·class="programlisting">struct·foo_data·{ |
793 | » KOBJ_FIELDS; | 793 | » KOBJ_FIELDS; |
794 | » foo_foo; | 794 | » foo_foo; |
795 | » foo_bar; | 795 | » foo_bar; |
796 | };</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60764984"></a>3.3.8. 调用方法</h3></div></div></div><p>使用Kobj的最后一部就是通过生成的函数调用对象类中的方法。 | 796 | };</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60763064"></a>3.3.8. 调用方法</h3></div></div></div><p>使用Kobj的最后一部就是通过生成的函数调用对象类中的方法。 |
797 | ········调用时,接口名与方法名用'_'接合,而且全部使用大写字母。</p><p>例如,接口名为foo,方法为bar,调用就是:</p><pre·class="programlisting">[返回值·=·]·FOO_BAR(对象·[,·其它参数]);</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60768952"></a>3.3.9. 善后处理</h3></div></div></div><p>当一个用<code·class="function">kobj_create()</code>不再需要被使用时, | 797 | ········调用时,接口名与方法名用'_'接合,而且全部使用大写字母。</p><p>例如,接口名为foo,方法为bar,调用就是:</p><pre·class="programlisting">[返回值·=·]·FOO_BAR(对象·[,·其它参数]);</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60768056"></a>3.3.9. 善后处理</h3></div></div></div><p>当一个用<code·class="function">kobj_create()</code>不再需要被使用时, |
798 | ········可对这个对象调用<code·class="function">kobj_delete()</code>。 | 798 | ········可对这个对象调用<code·class="function">kobj_delete()</code>。 |
799 | ········当一个类不再需要被使用时, | 799 | ········当一个类不再需要被使用时, |
800 | ········可对这个类调用<code·class="function">kobj_class_free()</code>。</p></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="jail"></a>第 4 章 Jail子系统</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div><div><span·xmlns="http://www.w3.org/1999/xhtml"·class="personname"><span·class="firstname">Evan</span>·<span·class="surname">Sarmiento</span></span><span·xmlns="http://www.w3.org/1999/xhtml"·class="affiliation"></span></div><div><p·xmlns="http://www.w3.org/1999/xhtml"·class="copyright">版权·©·2001·Evan·Sarmiento</p></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#jail-arch">4.1.·Jail的系统结构</a></span></dt><dt><span·class="sect1"><a·href="#jail-restrictions">4.2.·系统对被囚禁程序的限制</a></span></dt></dl></div><a·id="idp60788920"·class="indexterm"></a><a·id="idp60790072"·class="indexterm"></a><a·id="idp6079·✂ | 800 | ········可对这个类调用<code·class="function">kobj_class_free()</code>。</p></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="jail"></a>第 4 章 Jail子系统</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div><div><span·xmlns="http://www.w3.org/1999/xhtml"·class="personname"><span·class="firstname">Evan</span>·<span·class="surname">Sarmiento</span></span><span·xmlns="http://www.w3.org/1999/xhtml"·class="affiliation"></span></div><div><p·xmlns="http://www.w3.org/1999/xhtml"·class="copyright">版权·©·2001·Evan·Sarmiento</p></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#jail-arch">4.1.·Jail的系统结构</a></span></dt><dt><span·class="sect1"><a·href="#jail-restrictions">4.2.·系统对被囚禁程序的限制</a></span></dt></dl></div><a·id="idp60787128"·class="indexterm"></a><a·id="idp60788152"·class="indexterm"></a><a·id="idp6078·✂ |
801 | ····如果一个攻击者获得了一个系统中的<code·class="literal">root</code>,就可以在他的指尖掌握系统中所有的功能。 | 801 | ····如果一个攻击者获得了一个系统中的<code·class="literal">root</code>,就可以在他的指尖掌握系统中所有的功能。 |
802 | ····在FreeBSD里,有一些sysctl项削弱了<code·class="literal">root</code>的权限, | 802 | ····在FreeBSD里,有一些sysctl项削弱了<code·class="literal">root</code>的权限, |
803 | ····这样就可以将攻击者造成的损害减小到最低限度。这些安全功能中,有一种叫安全级别。 | 803 | ····这样就可以将攻击者造成的损害减小到最低限度。这些安全功能中,有一种叫安全级别。 |
804 | ····另一种在FreeBSD·4.0及以后版本中提供的安全功能,就是<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(8)</span></a>。 | 804 | ····另一种在FreeBSD·4.0及以后版本中提供的安全功能,就是<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(8)</span></a>。 |
805 | ····<span·class="application">Jail</span>将一个运行环境的文件树根切换到某一特定位置, | 805 | ····<span·class="application">Jail</span>将一个运行环境的文件树根切换到某一特定位置, |
806 | ····并且对这样环境中叉分生成的进程做出限制。例如, | 806 | ····并且对这样环境中叉分生成的进程做出限制。例如, |
807 | ····一个被监禁的进程不能影响这个<span·class="application">jail</span>之外的进程、不能使用一些特定的系统调用, | 807 | ····一个被监禁的进程不能影响这个<span·class="application">jail</span>之外的进程、不能使用一些特定的系统调用, |
Offset 812, 17 lines modified | Offset 812, 17 lines modified |
812 | ····这样一来,即使有攻击者取得了<span·class="application">jail</span>中的<code·class="literal">root</code>, | 812 | ····这样一来,即使有攻击者取得了<span·class="application">jail</span>中的<code·class="literal">root</code>, |
813 | ····这最多让人们皱皱眉头,而不会使人们惊慌失措。 | 813 | ····这最多让人们皱皱眉头,而不会使人们惊慌失措。 |
814 | ····本文主要关注<span·class="application">jail</span>的内部原理(源代码)。 | 814 | ····本文主要关注<span·class="application">jail</span>的内部原理(源代码)。 |
815 | ····如果你正在寻找设置<span·class="application">Jail</span>的指南性文档, | 815 | ····如果你正在寻找设置<span·class="application">Jail</span>的指南性文档, |
816 | ····我建议你阅读我的另一篇文章,发表在Sys·Admin·Magazine,·May·2001, | 816 | ····我建议你阅读我的另一篇文章,发表在Sys·Admin·Magazine,·May·2001, |
817 | ····《Securing·FreeBSD·using·<span·class="application">Jail</span>》。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="jail-arch"></a>4.1. Jail的系统结构</h2></div></div></div><p><span·class="application">Jail</span>由两部分组成:用户级程序, | 817 | ····《Securing·FreeBSD·using·<span·class="application">Jail</span>》。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="jail-arch"></a>4.1. Jail的系统结构</h2></div></div></div><p><span·class="application">Jail</span>由两部分组成:用户级程序, |
818 | ······也就是<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(8)</span></a>;还有在内核中Jail的实现代码:<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a> | 818 | ······也就是<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(8)</span></a>;还有在内核中Jail的实现代码:<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a> |
819 | ······系统调用和相关的约束。我将讨论用户级程序和<span·class="application">jail</span>在内核中的实现原理。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60819768"></a>4.1.1. 用户级代码</h3></div></div></div><a·id="idp60821560"·class="indexterm"></a><p><span·class="application">Jail</span>的用户级源代码在<code·class="filename">/usr/src/usr.sbin/jail</code>, | 819 | ······系统调用和相关的约束。我将讨论用户级程序和<span·class="application">jail</span>在内核中的实现原理。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60818360"></a>4.1.1. 用户级代码</h3></div></div></div><a·id="idp60837048"·class="indexterm"></a><p><span·class="application">Jail</span>的用户级源代码在<code·class="filename">/usr/src/usr.sbin/jail</code>, |
820 | ········由一个文件<code·class="filename">jail.c</code>组成。这个程序有这些参数:<span·class="application">jail</span>的路径, | 820 | ········由一个文件<code·class="filename">jail.c</code>组成。这个程序有这些参数:<span·class="application">jail</span>的路径, |
821 | ········主机名,IP地址,还有需要执行的命令。</p><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60840760"></a>4.1.1.1. 数据结构</h4></div></div></div><p>在<code·class="filename">jail.c</code>中,我将最先注解的是一个重要结构体 | 821 | ········主机名,IP地址,还有需要执行的命令。</p><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60843448"></a>4.1.1.1. 数据结构</h4></div></div></div><p>在<code·class="filename">jail.c</code>中,我将最先注解的是一个重要结构体 |
822 | ··········<code·class="literal">struct·jail·j;</code>的声明,这个结构类型的声明包含在 | 822 | ··········<code·class="literal">struct·jail·j;</code>的声明,这个结构类型的声明包含在 |
823 | ··········<code·class="filename">/usr/include/sys/jail.h</code>之中。</p><p><code·class="literal">jail</code>结构的定义是:</p><pre·class="programlisting"><code·class="filename">/usr/include/sys/jail.h</code>: | 823 | ··········<code·class="filename">/usr/include/sys/jail.h</code>之中。</p><p><code·class="literal">jail</code>结构的定义是:</p><pre·class="programlisting"><code·class="filename">/usr/include/sys/jail.h</code>: |
| |
824 | struct·jail·{ | 824 | struct·jail·{ |
825 | ········u_int32_t·······version; | 825 | ········u_int32_t·······version; |
826 | ········char············*path; | 826 | ········char············*path; |
827 | ········char············*hostname; | 827 | ········char············*hostname; |
Offset 834, 32 lines modified | Offset 834, 32 lines modified |
834 | if(realpath(argv[0],·path)·==·NULL) | 834 | if(realpath(argv[0],·path)·==·NULL) |
835 | ····err(1,·"realpath:·%s",·argv[0]); | 835 | ····err(1,·"realpath:·%s",·argv[0]); |
836 | if·(chdir(path)·!=·0) | 836 | if·(chdir(path)·!=·0) |
837 | ····err(1,·"chdir:·%s",·path); | 837 | ····err(1,·"chdir:·%s",·path); |
838 | memset(&j,·0,·sizeof(j)); | 838 | memset(&j,·0,·sizeof(j)); |
839 | j.version·=·0; | 839 | j.version·=·0; |
840 | j.path·=·path; | 840 | j.path·=·path; |
841 | j.hostname·=·argv[1];</pre></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60868280"></a>4.1.1.2. 网络</h4></div></div></div><p>传给<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(8)</span></a>的参数中有一个是IP地址。这是在网络上访问<span·class="application">jail</span>时的地址。 | 841 | j.hostname·=·argv[1];</pre></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp60884664"></a>4.1.1.2. 网络</h4></div></div></div><p>传给<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(8)</span></a>的参数中有一个是IP地址。这是在网络上访问<span·class="application">jail</span>时的地址。 |
842 | ··········<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(8)</span></a>将IP地址翻译成网络字节顺序,并存入<code·class="literal">j</code>(<code·class="literal">jail</code>类型的结构体)。</p><pre·class="programlisting"><code·class="filename">/usr/src/usr.sbin/jail/jail.c</code>: | 842 | ··········<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(8)</span></a>将IP地址翻译成网络字节顺序,并存入<code·class="literal">j</code>(<code·class="literal">jail</code>类型的结构体)。</p><pre·class="programlisting"><code·class="filename">/usr/src/usr.sbin/jail/jail.c</code>: |
843 | struct·in_addr·in; | 843 | struct·in_addr·in; |
844 | ... | 844 | ... |
845 | if·(inet_aton(argv[2],·&in)·==·0) | 845 | if·(inet_aton(argv[2],·&in)·==·0) |
846 | ····errx(1,·"Could·not·make·sense·of·ip-number:·%s",·argv[2]); | 846 | ····errx(1,·"Could·not·make·sense·of·ip-number:·%s",·argv[2]); |
847 | j.ip_number·=·ntohl(in.s_addr);</pre><p>函数<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=inet_aton&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">inet_aton</span>(3)</span></a>“将指定的字符串解释为一个Internet地址, | 847 | j.ip_number·=·ntohl(in.s_addr);</pre><p>函数<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=inet_aton&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">inet_aton</span>(3)</span></a>“将指定的字符串解释为一个Internet地址, |
848 | ··········并将其转存到指定的结构体中”。<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=inet_aton&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">inet_aton</span>(3)</span></a>设定了结构体in, | 848 | ··········并将其转存到指定的结构体中”。<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=inet_aton&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">inet_aton</span>(3)</span></a>设定了结构体in, |
849 | ··········之后in中的内容再用<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=ntohl&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">ntohl</span>(3)</span></a>转换成主机字节顺序, | 849 | ··········之后in中的内容再用<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=ntohl&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">ntohl</span>(3)</span></a>转换成主机字节顺序, |
850 | ··········并置入<code·class="literal">jail</code>结构体的<code·class="literal">ip_number</code>成员。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63313464"></a>4.1.1.3. 囚禁进程</h4></div></div></div><p>最后,用户级程序囚禁进程。现在Jail自身变成了一个被囚禁的进程, | 850 | ··········并置入<code·class="literal">jail</code>结构体的<code·class="literal">ip_number</code>成员。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63215160"></a>4.1.1.3. 囚禁进程</h4></div></div></div><p>最后,用户级程序囚禁进程。现在Jail自身变成了一个被囚禁的进程, |
851 | ··········并使用<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=execv&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">execv</span>(3)</span></a>执行用户指定的命令。</p><pre·class="programlisting"><code·class="filename">/usr/src/usr.sbin/jail/jail.c</code> | 851 | ··········并使用<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=execv&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">execv</span>(3)</span></a>执行用户指定的命令。</p><pre·class="programlisting"><code·class="filename">/usr/src/usr.sbin/jail/jail.c</code> |
852 | i·=·jail(&j); | 852 | i·=·jail(&j); |
853 | ... | 853 | ... |
854 | if·(execv(argv[3],·argv·+·3)·!=·0) | 854 | if·(execv(argv[3],·argv·+·3)·!=·0) |
855 | ····err(1,·"execv:·%s",·argv[3]);</pre><p>正如你所见,函数<code·class="literal">jail()</code>被调用,参数是结构体<code·class="literal">jail</code>中被填入数据项, | 855 | ····err(1,·"execv:·%s",·argv[3]);</pre><p>正如你所见,函数<code·class="literal">jail()</code>被调用,参数是结构体<code·class="literal">jail</code>中被填入数据项, |
856 | ·········而如前所述,这些数据项又来自<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(8)</span></a>的命令行参数。 | 856 | ·········而如前所述,这些数据项又来自<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(8)</span></a>的命令行参数。 |
857 | ·········最后,执行了用户指定的命令。下面我将开始讨论<code·class="literal">jail</code>在内核中的实现。</p></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63318456"></a>4.1.2. 相关的内核源代码</h3></div></div></div><a·id="idp63319096"·class="indexterm"></a><p>现在我们来看文件<code·class="filename">/usr/src/sys/kern/kern_jail.c</code>。 | 857 | ·········最后,执行了用户指定的命令。下面我将开始讨论<code·class="literal">jail</code>在内核中的实现。</p></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63297976"></a>4.1.2. 相关的内核源代码</h3></div></div></div><a·id="idp63298616"·class="indexterm"></a><p>现在我们来看文件<code·class="filename">/usr/src/sys/kern/kern_jail.c</code>。 |
858 | ········在这里定义了<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a>的系统调用、相关的sysctl项,还有网络函数。</p><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63321528"></a>4.1.2.1. sysctl项</h4></div></div></div><a·id="idp63322168"·class="indexterm"></a><p>在<code·class="filename">kern_jail.c</code>里定义了如下sysctl项:</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/kern/kern_jail.c:</code> | 858 | ········在这里定义了<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a>的系统调用、相关的sysctl项,还有网络函数。</p><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63301048"></a>4.1.2.1. sysctl项</h4></div></div></div><a·id="idp63301688"·class="indexterm"></a><p>在<code·class="filename">kern_jail.c</code>里定义了如下sysctl项:</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/kern/kern_jail.c:</code> |
| |
859 | int·····jail_set_hostname_allowed·=·1; | 859 | int·····jail_set_hostname_allowed·=·1; |
860 | SYSCTL_INT(_security_jail,·OID_AUTO,·set_hostname_allowed,·CTLFLAG_RW, | 860 | SYSCTL_INT(_security_jail,·OID_AUTO,·set_hostname_allowed,·CTLFLAG_RW, |
861 | ····&jail_set_hostname_allowed,·0, | 861 | ····&jail_set_hostname_allowed,·0, |
862 | ····"Processes·in·jail·can·set·their·hostnames"); | 862 | ····"Processes·in·jail·can·set·their·hostnames"); |
863 | ····/*·Jail中的进程可设定自身的主机名·*/ | 863 | ····/*·Jail中的进程可设定自身的主机名·*/ |
| |
Offset 895, 15 lines modified | Offset 895, 15 lines modified |
| |
895 | int·····jail_mount_allowed·=·0; | 895 | int·····jail_mount_allowed·=·0; |
896 | SYSCTL_INT(_security_jail,·OID_AUTO,·mount_allowed,·CTLFLAG_RW, | 896 | SYSCTL_INT(_security_jail,·OID_AUTO,·mount_allowed,·CTLFLAG_RW, |
897 | ····&jail_mount_allowed,·0, | 897 | ····&jail_mount_allowed,·0, |
898 | ····"Processes·in·jail·can·mount/unmount·jail-friendly·file·systems"); | 898 | ····"Processes·in·jail·can·mount/unmount·jail-friendly·file·systems"); |
899 | ····/*·jail·中的进程是否可以挂载或卸载对jail友好的文件系统·*/</pre><p>这些sysctl项中的每一个都可以用命令<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=sysctl&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">sysctl</span>(8)</span></a>访问。在整个内核中, | 899 | ····/*·jail·中的进程是否可以挂载或卸载对jail友好的文件系统·*/</pre><p>这些sysctl项中的每一个都可以用命令<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=sysctl&sektion=8&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">sysctl</span>(8)</span></a>访问。在整个内核中, |
900 | ··········这些sysctl项按名称标识。例如,上述第一个sysctl项的名字是 | 900 | ··········这些sysctl项按名称标识。例如,上述第一个sysctl项的名字是 |
901 | ··········<code·class="literal">security.jail.set_hostname_allowed</code>。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63325752"></a>4.1.2.2. <a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a>系统调用</h4></div></div></div><p>像所有的系统调用一样,系统调用<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a>带有两个参数, | 901 | ··········<code·class="literal">security.jail.set_hostname_allowed</code>。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63305272"></a>4.1.2.2. <a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a>系统调用</h4></div></div></div><p>像所有的系统调用一样,系统调用<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a>带有两个参数, |
902 | ··········<code·class="literal">struct·thread·*td</code>和<code·class="literal">struct·jail_args·*uap</code>。 | 902 | ··········<code·class="literal">struct·thread·*td</code>和<code·class="literal">struct·jail_args·*uap</code>。 |
903 | ··········<code·class="literal">td</code>是一个指向<code·class="literal">thread</code>结构体的指针,该指针用于描述调用<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a>的线程。 | 903 | ··········<code·class="literal">td</code>是一个指向<code·class="literal">thread</code>结构体的指针,该指针用于描述调用<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a>的线程。 |
904 | ··········在这个上下文中,<code·class="literal">uap</code>指向一个结构体,这个结构体中包含了一个指向从用户级 | 904 | ··········在这个上下文中,<code·class="literal">uap</code>指向一个结构体,这个结构体中包含了一个指向从用户级 |
905 | ··········<code·class="filename">jail.c</code>传送过来的<code·class="literal">jail</code>结构体的指针。 | 905 | ··········<code·class="filename">jail.c</code>传送过来的<code·class="literal">jail</code>结构体的指针。 |
906 | ··········在前面我讲述用户级程序时,你已经看到过一个<code·class="literal">jail</code>结构体被作为参数传送给系统调用 | 906 | ··········在前面我讲述用户级程序时,你已经看到过一个<code·class="literal">jail</code>结构体被作为参数传送给系统调用 |
907 | ··········<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a>。</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/kern/kern_jail.c:</code> | 907 | ··········<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=jail&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">jail</span>(2)</span></a>。</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/kern/kern_jail.c:</code> |
908 | /* | 908 | /* |
Offset 1022, 42 lines modified | Offset 1022, 42 lines modified |
1022 | ··········这样,很自然的就保持了子进程的身份凭证于其父进程一致,所以子进程也是被监禁的。</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/kern/kern_fork.c</code>: | 1022 | ··········这样,很自然的就保持了子进程的身份凭证于其父进程一致,所以子进程也是被监禁的。</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/kern/kern_fork.c</code>: |
1023 | p2->p_ucred·=·crhold(td->td_ucred); | 1023 | p2->p_ucred·=·crhold(td->td_ucred); |
1024 | ... | 1024 | ... |
1025 | td2->td_ucred·=·crhold(p2->p_ucred);</pre></div></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="jail-restrictions"></a>4.2. 系统对被囚禁程序的限制</h2></div></div></div><p>在整个内核中,有一系列对被囚禁程序的约束措施。 | 1025 | td2->td_ucred·=·crhold(p2->p_ucred);</pre></div></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="jail-restrictions"></a>4.2. 系统对被囚禁程序的限制</h2></div></div></div><p>在整个内核中,有一系列对被囚禁程序的约束措施。 |
1026 | ······通常,这些约束只对被囚禁的程序有效。如果这些程序试图突破这些约束, | 1026 | ······通常,这些约束只对被囚禁的程序有效。如果这些程序试图突破这些约束, |
1027 | ······相关的函数将出错返回。例如:</p><pre·class="programlisting"> | 1027 | ······相关的函数将出错返回。例如:</p><pre·class="programlisting"> |
1028 | if·(jailed(td->td_ucred)) | 1028 | if·(jailed(td->td_ucred)) |
1029 | ····return·EPERM;</pre><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63408440"></a>4.2.1. SysV进程间通信(IPC)</h3></div></div></div><a·id="idp63409080"·class="indexterm"></a><p>System·V·进程间通信·(IPC)·是通过消息实现的。 | 1029 | ····return·EPERM;</pre><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63387960"></a>4.2.1. SysV进程间通信(IPC)</h3></div></div></div><a·id="idp63392696"·class="indexterm"></a><p>System·V·进程间通信·(IPC)·是通过消息实现的。 |
1030 | ········每个进程都可以向其它进程发送消息,·告诉对方该做什么。 | 1030 | ········每个进程都可以向其它进程发送消息,·告诉对方该做什么。 |
1031 | ········处理消息的函数是:·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=msgctl&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">msgctl</span>(3)</span></a>、<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=msgget&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">msgget</span>(3)</span></a>、<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=msgsnd&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">msgsnd</span>(3)</span></a>·和 | 1031 | ········处理消息的函数是:·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=msgctl&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">msgctl</span>(3)</span></a>、<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=msgget&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">msgget</span>(3)</span></a>、<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=msgsnd&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">msgsnd</span>(3)</span></a>·和 |
1032 | ················<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=msgrcv&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">msgrcv</span>(3)</span></a>。前面已经提到,一些·sysctl·开关可以影响·<span·class="application">jail</span>·的行为, | 1032 | ················<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=msgrcv&sektion=3&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">msgrcv</span>(3)</span></a>。前面已经提到,一些·sysctl·开关可以影响·<span·class="application">jail</span>·的行为, |
1033 | ········其中有一个是·<code·class="literal">security.jail.sysvipc_allowed</code>。·在大多数系统上, | 1033 | ········其中有一个是·<code·class="literal">security.jail.sysvipc_allowed</code>。·在大多数系统上, |
1034 | ········这个·sysctl·项会设成0。·如果将它设为1,·则会完全失去·<span·class="application">jail</span>·的意义: | 1034 | ········这个·sysctl·项会设成0。·如果将它设为1,·则会完全失去·<span·class="application">jail</span>·的意义: |
1035 | ········因为那样在·<span·class="application">jail</span>·中特权进程就可以影响被监禁的环境外的进程了。 | 1035 | ········因为那样在·<span·class="application">jail</span>·中特权进程就可以影响被监禁的环境外的进程了。 |
1036 | ········消息与信号的区别是:消息仅由一个信号编号组成。</p><p><code·class="filename">/usr/src/sys/kern/sysv_msg.c</code>:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><code·class="literal">msgget(key,·msgflg)</code>: | 1036 | ········消息与信号的区别是:消息仅由一个信号编号组成。</p><p><code·class="filename">/usr/src/sys/kern/sysv_msg.c</code>:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><code·class="literal">msgget(key,·msgflg)</code>: |
1037 | ······················<code·class="literal">msgget</code>返回(也可能创建)一个消息描述符, | 1037 | ······················<code·class="literal">msgget</code>返回(也可能创建)一个消息描述符, |
1038 | ···········以指派一个在其它函数中使用的消息队列。</p></li><li·class="listitem"><p><code·class="literal">msgctl(msgid,·cmd,·buf)</code>:·通过这个函数, | 1038 | ···········以指派一个在其它函数中使用的消息队列。</p></li><li·class="listitem"><p><code·class="literal">msgctl(msgid,·cmd,·buf)</code>:·通过这个函数, |
1039 | ···········一个进程可以查询一个消息描述符的状态。</p></li><li·class="listitem"><p><code·class="literal">msgsnd(msgid,·msgp,·msgsz,·msgflg)</code>: | 1039 | ···········一个进程可以查询一个消息描述符的状态。</p></li><li·class="listitem"><p><code·class="literal">msgsnd(msgid,·msgp,·msgsz,·msgflg)</code>: |
1040 | ·····················<code·class="literal">msgsnd</code>向一个进程发送一条消息。</p></li><li·class="listitem"><p><code·class="literal">msgrcv(msgid,·msgp,·msgsz,·msgtyp,·msgflg)</code>: | 1040 | ·····················<code·class="literal">msgsnd</code>向一个进程发送一条消息。</p></li><li·class="listitem"><p><code·class="literal">msgrcv(msgid,·msgp,·msgsz,·msgtyp,·msgflg)</code>: |
1041 | ···········进程用这个函数接收消息。</p></li></ul></div><p>在这些函数对应的系统调用的代码中,都有这样一个条件判断:</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/kern/sysv_msg.c</code>: | 1041 | ···········进程用这个函数接收消息。</p></li></ul></div><p>在这些函数对应的系统调用的代码中,都有这样一个条件判断:</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/kern/sysv_msg.c</code>: |
1042 | if·(!jail_sysvipc_allowed·&&·jailed(td->td_ucred)) | 1042 | if·(!jail_sysvipc_allowed·&&·jailed(td->td_ucred)) |
1043 | ····return·(ENOSYS);</pre><a·id="idp63424696"·class="indexterm"></a><p>信号量系统调用使得进程可以通过一系列原子操作实现同步。 | 1043 | ····return·(ENOSYS);</pre><a·id="idp63404216"·class="indexterm"></a><p>信号量系统调用使得进程可以通过一系列原子操作实现同步。 |
1044 | ·········信号量为进程锁定资源提供了又一种途径。 | 1044 | ·········信号量为进程锁定资源提供了又一种途径。 |
1045 | ·········然而,进程将为正在被使用的信号量进入等待状态,一直休眠到资源被释放。 | 1045 | ·········然而,进程将为正在被使用的信号量进入等待状态,一直休眠到资源被释放。 |
1046 | ·········在<span·class="application">jail</span>中如下的信号量系统调用将会失效:·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=semget&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">semget</span>(2)</span></a>,·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=semctl&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">semctl</span>(2)</span></a> | 1046 | ·········在<span·class="application">jail</span>中如下的信号量系统调用将会失效:·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=semget&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">semget</span>(2)</span></a>,·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=semctl&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">semctl</span>(2)</span></a> |
1047 | ·········和<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=semop&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">semop</span>(2)</span></a>。</p><p><code·class="filename">/usr/src/sys/kern/sysv_sem.c</code>:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><code·class="literal">semctl(semid,·num,·cmd,·...)</code>: | 1047 | ·········和<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=semop&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">semop</span>(2)</span></a>。</p><p><code·class="filename">/usr/src/sys/kern/sysv_sem.c</code>:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><code·class="literal">semctl(semid,·num,·cmd,·...)</code>: |
1048 | ············<code·class="literal">semctl</code>对在信号量队列中用<code·class="literal">semid</code>标识的信号量执行<code·class="literal">cmd</code>指定的命令。</p></li><li·class="listitem"><p><code·class="literal">semget(key,·nsems,·flag)</code>: | 1048 | ············<code·class="literal">semctl</code>对在信号量队列中用<code·class="literal">semid</code>标识的信号量执行<code·class="literal">cmd</code>指定的命令。</p></li><li·class="listitem"><p><code·class="literal">semget(key,·nsems,·flag)</code>: |
1049 | ············<code·class="literal">semget</code>建立一个对应于<code·class="literal">key</code>的信号量数组。</p><p><code·class="literal">参数key和flag与他们在msgget()的意义相同。</code></p></li><li·class="listitem"><p><code·class="literal">setop(semid,·array,·nops)</code>: | 1049 | ············<code·class="literal">semget</code>建立一个对应于<code·class="literal">key</code>的信号量数组。</p><p><code·class="literal">参数key和flag与他们在msgget()的意义相同。</code></p></li><li·class="listitem"><p><code·class="literal">setop(semid,·array,·nops)</code>: |
1050 | ··········<code·class="literal">semop</code>对semid标识的信号量完成一组由array所指定的操作。</p></li></ul></div><a·id="idp63193016"·class="indexterm"></a><p>System·V·IPC使进程间可以共享内存。进程之间可以通过它们虚拟地址空间 | 1050 | ··········<code·class="literal">semop</code>对semid标识的信号量完成一组由array所指定的操作。</p></li></ul></div><a·id="idp63418296"·class="indexterm"></a><p>System·V·IPC使进程间可以共享内存。进程之间可以通过它们虚拟地址空间 |
1051 | ·········的共享部分以及相关数据读写操作直接通讯。这些系统调用在被监禁的环境中将会失效: | 1051 | ·········的共享部分以及相关数据读写操作直接通讯。这些系统调用在被监禁的环境中将会失效: |
1052 | ··················<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=shmdt&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">shmdt</span>(2)</span></a>、<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=shmat&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">shmat</span>(2)</span></a>、<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=shmctl&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">shmctl</span>(2)</span></a>和<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=shmget&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">shmget</span>(2)</span></a></p><p><code·class="filename">/usr/src/sys/kern/sysv_shm.c</code>:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listite·✂ | 1052 | ··················<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=shmdt&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">shmdt</span>(2)</span></a>、<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=shmat&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">shmat</span>(2)</span></a>、<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=shmctl&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">shmctl</span>(2)</span></a>和<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=shmget&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">shmget</span>(2)</span></a></p><p><code·class="filename">/usr/src/sys/kern/sysv_shm.c</code>:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listite·✂ |
1053 | ········<code·class="literal">shmctl</code>对<code·class="literal">id</code>标识的共享内存区域做各种各样的控制。</p></li><li·class="listitem"><p><code·class="literal">shmget(key,·size,·flag)</code>: | 1053 | ········<code·class="literal">shmctl</code>对<code·class="literal">id</code>标识的共享内存区域做各种各样的控制。</p></li><li·class="listitem"><p><code·class="literal">shmget(key,·size,·flag)</code>: |
1054 | ········<code·class="literal">shmget</code>建立/打开<code·class="literal">size</code>字节的共享内存区域。</p></li><li·class="listitem"><p><code·class="literal">shmat(shmid,·addr,·flag)</code>: | 1054 | ········<code·class="literal">shmget</code>建立/打开<code·class="literal">size</code>字节的共享内存区域。</p></li><li·class="listitem"><p><code·class="literal">shmat(shmid,·addr,·flag)</code>: |
1055 | ········<code·class="literal">shmat</code>将<code·class="literal">shmid</code>标识的共享内存区域指派到进程的地址空间里。</p></li><li·class="listitem"><p><code·class="literal">shmdt(addr)</code>: | 1055 | ········<code·class="literal">shmat</code>将<code·class="literal">shmid</code>标识的共享内存区域指派到进程的地址空间里。</p></li><li·class="listitem"><p><code·class="literal">shmdt(addr)</code>: |
1056 | ········<code·class="literal">shmdt</code>取消共享内存区域的地址指派。</p></li></ul></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63207864"></a>4.2.2. 套接字</h3></div></div></div><a·id="idp63433784"·class="indexterm"></a><p><span·class="application">Jail</span>以一种特殊的方式处理<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=socket&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">socket</span>(2)</span></a>系统调用和相关的低级套接字函数。 | 1056 | ········<code·class="literal">shmdt</code>取消共享内存区域的地址指派。</p></li></ul></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63433144"></a>4.2.2. 套接字</h3></div></div></div><a·id="idp63433784"·class="indexterm"></a><p><span·class="application">Jail</span>以一种特殊的方式处理<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=socket&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">socket</span>(2)</span></a>系统调用和相关的低级套接字函数。 |
1057 | ·········为了决定一个套接字是否允许被创建,它先检查sysctl项 | 1057 | ·········为了决定一个套接字是否允许被创建,它先检查sysctl项 |
1058 | ·················<code·class="literal">security.jail.socket_unixiproute_only</code>是否被设置为1。 | 1058 | ·················<code·class="literal">security.jail.socket_unixiproute_only</code>是否被设置为1。 |
1059 | ·········如果被设为1,套接字建立时将只能指定这些协议族: | 1059 | ·········如果被设为1,套接字建立时将只能指定这些协议族: |
1060 | ··················<code·class="literal">PF_LOCAL</code>,·<code·class="literal">PF_INET</code>, | 1060 | ··················<code·class="literal">PF_LOCAL</code>,·<code·class="literal">PF_INET</code>, |
1061 | ··················<code·class="literal">PF_ROUTE</code>。否则,<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=socket&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">socket</span>(2)</span></a>将会返回出错。</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/kern/uipc_socket.c</code>: | 1061 | ··················<code·class="literal">PF_ROUTE</code>。否则,<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=socket&sektion=2&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">socket</span>(2)</span></a>将会返回出错。</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/kern/uipc_socket.c</code>: |
1062 | int | 1062 | int |
1063 | socreate(int·dom,·struct·socket·**aso,·int·type,·int·proto, | 1063 | socreate(int·dom,·struct·socket·**aso,·int·type,·int·proto, |
Offset 1142, 15 lines modified | Offset 1142, 15 lines modified |
1142 | ········else | 1142 | ········else |
1143 | ············*ip·=·htonl(cred->cr_prison->pr_ip); | 1143 | ············*ip·=·htonl(cred->cr_prison->pr_ip); |
1144 | ········return·(0); | 1144 | ········return·(0); |
1145 | ····} | 1145 | ····} |
1146 | ····if·(cred->cr_prison->pr_ip·!=·tmp) | 1146 | ····if·(cred->cr_prison->pr_ip·!=·tmp) |
1147 | ········return·(1); | 1147 | ········return·(1); |
1148 | ····return·(0); | 1148 | ····return·(0); |
1149 | }</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63484344"></a>4.2.5. 文件系统</h3></div></div></div><a·id="idp63484984"·class="indexterm"></a><p>如果完全级别大于0,即便是<span·class="application">jail</span>里面的<code·class="literal">root</code>, | 1149 | }</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63451576"></a>4.2.5. 文件系统</h3></div></div></div><a·id="idp63452216"·class="indexterm"></a><p>如果完全级别大于0,即便是<span·class="application">jail</span>里面的<code·class="literal">root</code>, |
1150 | ········也不允许在Jail中取消或更改文件标志,如“不可修改”、“只可添加”、“不可删除”标志。</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/ufs/ufs/ufs_vnops.c:</code> | 1150 | ········也不允许在Jail中取消或更改文件标志,如“不可修改”、“只可添加”、“不可删除”标志。</p><pre·class="programlisting"><code·class="filename">/usr/src/sys/ufs/ufs/ufs_vnops.c:</code> |
1151 | static·int | 1151 | static·int |
1152 | ufs_setattr(ap) | 1152 | ufs_setattr(ap) |
1153 | ····... | 1153 | ····... |
1154 | { | 1154 | { |
1155 | ····... | 1155 | ····... |
1156 | ········if·(!priv_check_cred(cred,·PRIV_VFS_SYSFLAGS,·0))·{ | 1156 | ········if·(!priv_check_cred(cred,·PRIV_VFS_SYSFLAGS,·0))·{ |
Offset 1184, 47 lines modified | Offset 1184, 47 lines modified |
1184 | ········if·(jail_chflags_allowed) | 1184 | ········if·(jail_chflags_allowed) |
1185 | ············return·(0); | 1185 | ············return·(0); |
1186 | ········else | 1186 | ········else |
1187 | ············return·(EPERM); | 1187 | ············return·(EPERM); |
1188 | ····... | 1188 | ····... |
1189 | ····} | 1189 | ····} |
1190 | ····... | 1190 | ····... |
1191 | }</pre></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="sysinit"></a>第 5 章 SYSINIT框架</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#sysinit-term">5.1.·术语</a></span></dt><dt><span·class="sect1"><a·href="#sysinit-operation">5.2.·SYSINIT操作</a></span></dt><dt><span·class="sect1"><a·href="#sysinit-using">5.3.·使用SYSINIT</a></span></dt></dl></div><a·id="idp63494968"·class="indexterm"></a><a·id="idp63495480"·class="indexterm"></a><a·id="idp63495992"·class="indexterm"></a><a·id="idp63496888"·class="indexterm"></a><a·id="idp63497400"·class="indexterm"></a><p>SYSINIT是一个通用的调用排序与分别执行机制的框架。 | 1191 | }</pre></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="sysinit"></a>第 5 章 SYSINIT框架</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#sysinit-term">5.1.·术语</a></span></dt><dt><span·class="sect1"><a·href="#sysinit-operation">5.2.·SYSINIT操作</a></span></dt><dt><span·class="sect1"><a·href="#sysinit-using">5.3.·使用SYSINIT</a></span></dt></dl></div><a·id="idp63462200"·class="indexterm"></a><a·id="idp63462712"·class="indexterm"></a><a·id="idp63463224"·class="indexterm"></a><a·id="idp63464120"·class="indexterm"></a><a·id="idp63464632"·class="indexterm"></a><p>SYSINIT是一个通用的调用排序与分别执行机制的框架。 |
1192 | ····FreeBSD目前使用它来进行内核的动态初始化。 | 1192 | ····FreeBSD目前使用它来进行内核的动态初始化。 |
1193 | ····SYSINIT使得FreeBSD的内核各子系统可以在内核或模块动态加载链接时被重整、 | 1193 | ····SYSINIT使得FreeBSD的内核各子系统可以在内核或模块动态加载链接时被重整、 |
1194 | ····添加、删除、替换,这样,内核和模块加载时就不必去修改一个静态的有序初始化 | 1194 | ····添加、删除、替换,这样,内核和模块加载时就不必去修改一个静态的有序初始化 |
1195 | ····安排表甚至重新编译内核。这个体系也使得内核模块 | 1195 | ····安排表甚至重新编译内核。这个体系也使得内核模块 |
1196 | ····(现在称为<em·class="firstterm">KLD</em>可以与内核不同时编译、链接、 | 1196 | ····(现在称为<em·class="firstterm">KLD</em>可以与内核不同时编译、链接、 |
1197 | ····在引导系统时加载,甚至在系统运行时加载。这些操作是通过 | 1197 | ····在引导系统时加载,甚至在系统运行时加载。这些操作是通过 |
1198 | ····<span·class="quote">“<span·class="quote">内核链接器</span>”</span>(kernel·linker)和<span·class="quote">“<span·class="quote">链接器集合</span>”</span> | 1198 | ····<span·class="quote">“<span·class="quote">内核链接器</span>”</span>(kernel·linker)和<span·class="quote">“<span·class="quote">链接器集合</span>”</span> |
1199 | ····(linker·set)完成的。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="sysinit-term"></a>5.1. 术语</h2></div></div></div><div·class="variablelist"><dl·class="variablelist"><dt><span·class="term">链接器集合(Linker·Set)</span></dt><dd><p>一种链接方法。这种方法将整个程序源文件中静态申明的数据收集到 | 1199 | ····(linker·set)完成的。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="sysinit-term"></a>5.1. 术语</h2></div></div></div><div·class="variablelist"><dl·class="variablelist"><dt><span·class="term">链接器集合(Linker·Set)</span></dt><dd><p>一种链接方法。这种方法将整个程序源文件中静态申明的数据收集到 |
1200 | ·············一个可邻近寻址的数据单元中。</p></dd></dl></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="sysinit-operation"></a>5.2. SYSINIT操作</h2></div></div></div><a·id="idp63503032"·class="indexterm"></a><p>SYSINIT要依靠链接器获取遍布整个程序源代码多处申明的静态数据 | 1200 | ·············一个可邻近寻址的数据单元中。</p></dd></dl></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="sysinit-operation"></a>5.2. SYSINIT操作</h2></div></div></div><a·id="idp63470264"·class="indexterm"></a><p>SYSINIT要依靠链接器获取遍布整个程序源代码多处申明的静态数据 |
1201 | ······并把它们组成一个彼此相邻的数据块。这种链接方法被称为 | 1201 | ······并把它们组成一个彼此相邻的数据块。这种链接方法被称为 |
1202 | ······<span·class="quote">“<span·class="quote">链接器集合</span>”</span>(linker·set)。 | 1202 | ······<span·class="quote">“<span·class="quote">链接器集合</span>”</span>(linker·set)。 |
1203 | ······SYSINIT使用两个链接器集合以维护两个数据集合, | 1203 | ······SYSINIT使用两个链接器集合以维护两个数据集合, |
1204 | ······包含每个数据条目的调用顺序、函数、一个会被提交给该函数的数据指针。</p><p>SYSINIT按照两类优先级标识对函数排序以便执行。 | 1204 | ······包含每个数据条目的调用顺序、函数、一个会被提交给该函数的数据指针。</p><p>SYSINIT按照两类优先级标识对函数排序以便执行。 |
1205 | ······第一类优先级的标识是子系统的标识, | 1205 | ······第一类优先级的标识是子系统的标识, |
1206 | ······给出SYSINIT分别执行子系统的函数的全局顺序, | 1206 | ······给出SYSINIT分别执行子系统的函数的全局顺序, |
1207 | ······定义在<code·class="filename"><sys/kernel.h></code>中的枚举 | 1207 | ······定义在<code·class="filename"><sys/kernel.h></code>中的枚举 |
1208 | ······<code·class="literal">sysinit_sub_id</code>内。第二类优先级标识在子系统中的元素的顺序, | 1208 | ······<code·class="literal">sysinit_sub_id</code>内。第二类优先级标识在子系统中的元素的顺序, |
1209 | ······定义在<code·class="filename"><sys/kernel.h></code>中的枚举 | 1209 | ······定义在<code·class="filename"><sys/kernel.h></code>中的枚举 |
1210 | ······<code·class="literal">sysinit_elem_order</code>内。</p><a·id="idp63506232"·class="indexterm"></a><p>有两种时刻需要使用SYSINIT:系统启动或内核模块加载时, | 1210 | ······<code·class="literal">sysinit_elem_order</code>内。</p><a·id="idp63485752"·class="indexterm"></a><p>有两种时刻需要使用SYSINIT:系统启动或内核模块加载时, |
1211 | ······系统析构或内核模块卸载时。内核子系统通常在系统启动时使用SYSINIT | 1211 | ······系统析构或内核模块卸载时。内核子系统通常在系统启动时使用SYSINIT |
1212 | ······的定义项以初始化数据结构。例如,进程调度子系统使用一个SYSINIT | 1212 | ······的定义项以初始化数据结构。例如,进程调度子系统使用一个SYSINIT |
1213 | ······定义项来初始化运行队列数据结构。设备驱动程序应避免直接使用 | 1213 | ······定义项来初始化运行队列数据结构。设备驱动程序应避免直接使用 |
1214 | ······<code·class="literal">SYSINIT()</code>,对于总线结构上的物理真实设备应使用 | 1214 | ······<code·class="literal">SYSINIT()</code>,对于总线结构上的物理真实设备应使用 |
1215 | ······<code·class="literal">DRIVER_MODULE()</code>调用的函数先侦测设备的存在, | 1215 | ······<code·class="literal">DRIVER_MODULE()</code>调用的函数先侦测设备的存在, |
1216 | ······如果存在,再进行设备的初始化。这一系统过程中, | 1216 | ······如果存在,再进行设备的初始化。这一系统过程中, |
1217 | ······会做一些专门针对设备的事情,然后调用<code·class="literal">SYSINIT()</code>本身。 | 1217 | ······会做一些专门针对设备的事情,然后调用<code·class="literal">SYSINIT()</code>本身。 |
1218 | ······对于非总线结构一部分的虚设备,应改用<code·class="literal">DEV_MODULE()</code>。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="sysinit-using"></a>5.3. 使用SYSINIT</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63509560"></a>5.3.1. 接口</h3></div></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63510200"></a>5.3.1.1. 头文件</h4></div></div></div><pre·class="programlisting"><sys/kernel.h></pre></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63511352"></a>5.3.1.2. 宏</h4></div></div></div><pre·class="programlisting">SYSINIT(uniquifier,·subsystem,·order,·func,·ident) | 1218 | ······对于非总线结构一部分的虚设备,应改用<code·class="literal">DEV_MODULE()</code>。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="sysinit-using"></a>5.3. 使用SYSINIT</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63489080"></a>5.3.1. 接口</h3></div></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63489720"></a>5.3.1.1. 头文件</h4></div></div></div><pre·class="programlisting"><sys/kernel.h></pre></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63490872"></a>5.3.1.2. 宏</h4></div></div></div><pre·class="programlisting">SYSINIT(uniquifier,·subsystem,·order,·func,·ident) |
1219 | SYSUNINIT(uniquifier,·subsystem,·order,·func,·ident)</pre></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63512632"></a>5.3.2. 启动</h3></div></div></div><p>宏<code·class="literal">SYSINIT()</code>在SYSINIT启动数据集合中 | 1219 | SYSUNINIT(uniquifier,·subsystem,·order,·func,·ident)</pre></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63492152"></a>5.3.2. 启动</h3></div></div></div><p>宏<code·class="literal">SYSINIT()</code>在SYSINIT启动数据集合中 |
1220 | ········建立一个SYSINIT数据项,以便SYSINIT在系统启动或模块加载时排序 | 1220 | ········建立一个SYSINIT数据项,以便SYSINIT在系统启动或模块加载时排序 |
1221 | ········并执行其中的函数。<code·class="literal">SYSINIT()</code>有一个参数uniquifier, | 1221 | ········并执行其中的函数。<code·class="literal">SYSINIT()</code>有一个参数uniquifier, |
1222 | ········SYSINIT用它来标识数据项,随后是子系统顺序号、子系统元素顺序号、 | 1222 | ········SYSINIT用它来标识数据项,随后是子系统顺序号、子系统元素顺序号、 |
1223 | ········待调用函数、传递给函数的数据。所有的函数必须有一个恒量指针参数。</p><div·class="example"><a·id="idp63514424"></a><div·class="example-title">例 5.1. <code·class="literal">SYSINIT()</code>的例子</div><div·class="example-contents"><pre·class="programlisting">#include·<sys/kernel.h> | 1223 | ········待调用函数、传递给函数的数据。所有的函数必须有一个恒量指针参数。</p><div·class="example"><a·id="idp63493944"></a><div·class="example-title">例 5.1. <code·class="literal">SYSINIT()</code>的例子</div><div·class="example-contents"><pre·class="programlisting">#include·<sys/kernel.h> |
| |
1224 | void·foo_null(void·*unused) | 1224 | void·foo_null(void·*unused) |
1225 | { | 1225 | { |
1226 | ········foo_doo(); | 1226 | ········foo_doo(); |
1227 | } | 1227 | } |
1228 | SYSINIT(foo,·SI_SUB_FOO,·SI_ORDER_FOO,·foo_null,·NULL); | 1228 | SYSINIT(foo,·SI_SUB_FOO,·SI_ORDER_FOO,·foo_null,·NULL); |
| |
Offset 1239, 23 lines modified | Offset 1239, 23 lines modified |
1239 | } | 1239 | } |
1240 | SYSINIT(bar,·SI_SUB_FOO,·SI_ORDER_FOO,·foo_arg,·&foo_voodoo); | 1240 | SYSINIT(bar,·SI_SUB_FOO,·SI_ORDER_FOO,·foo_arg,·&foo_voodoo); |
1241 | » </pre></div></div><br·class="example-break"·/><p>注意,<code·class="literal">SI_SUB_FOO</code>和<code·class="literal">SI_ORDER_FOO</code> | 1241 | » </pre></div></div><br·class="example-break"·/><p>注意,<code·class="literal">SI_SUB_FOO</code>和<code·class="literal">SI_ORDER_FOO</code> |
1242 | ·········应当分别在上面提到的枚举<code·class="literal">sysinit_sub_id</code>和 | 1242 | ·········应当分别在上面提到的枚举<code·class="literal">sysinit_sub_id</code>和 |
1243 | ·········<code·class="literal">sysinit_elem_order</code>之中。既可以使用已有的枚举项, | 1243 | ·········<code·class="literal">sysinit_elem_order</code>之中。既可以使用已有的枚举项, |
1244 | ·········也可以将自己的枚举项添加到这两个枚举的定义之中。 | 1244 | ·········也可以将自己的枚举项添加到这两个枚举的定义之中。 |
1245 | ·········你可以使用数学表达式微调SYSINIT的执行顺序。 | 1245 | ·········你可以使用数学表达式微调SYSINIT的执行顺序。 |
1246 | ·········以下的例子示例了一个需要刚好要在内核参数调整的SYSINIT之前执行的SYSINIT。</p><div·class="example"><a·id="idp63517752"></a><div·class="example-title">例 5.2. 调整<code·class="literal">SYSINIT()</code>顺序的例子</div><div·class="example-contents"><pre·class="programlisting">static·void | 1246 | ·········以下的例子示例了一个需要刚好要在内核参数调整的SYSINIT之前执行的SYSINIT。</p><div·class="example"><a·id="idp63497272"></a><div·class="example-title">例 5.2. 调整<code·class="literal">SYSINIT()</code>顺序的例子</div><div·class="example-contents"><pre·class="programlisting">static·void |
1247 | mptable_register(void·*dummy·__unused) | 1247 | mptable_register(void·*dummy·__unused) |
1248 | { | 1248 | { |
| |
1249 | » apic_register_enumerator(&mptable_enumerator); | 1249 | » apic_register_enumerator(&mptable_enumerator); |
1250 | } | 1250 | } |
| |
1251 | SYSINIT(mptable_register,·SI_SUB_TUNABLES·-·1,·SI_ORDER_FIRST, | 1251 | SYSINIT(mptable_register,·SI_SUB_TUNABLES·-·1,·SI_ORDER_FIRST, |
1252 | ····mptable_register,·NULL);</pre></div></div><br·class="example-break"·/></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63519416"></a>5.3.3. 析构</h3></div></div></div><p>宏<code·class="literal">SYSUNINIT()</code>的行为与<code·class="literal">SYSINIT()</code>的相当, | 1252 | ····mptable_register,·NULL);</pre></div></div><br·class="example-break"·/></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp63498936"></a>5.3.3. 析构</h3></div></div></div><p>宏<code·class="literal">SYSUNINIT()</code>的行为与<code·class="literal">SYSINIT()</code>的相当, |
1253 | ········只是它将数据项填加至SYSINIT的析构数据集合。</p><div·class="example"><a·id="idp63521208"></a><div·class="example-title">例 5.3. <code·class="literal">SYSUNINIT()</code>的例子</div><div·class="example-contents"><pre·class="programlisting">#include·<sys/kernel.h> | 1253 | ········只是它将数据项填加至SYSINIT的析构数据集合。</p><div·class="example"><a·id="idp63521208"></a><div·class="example-title">例 5.3. <code·class="literal">SYSUNINIT()</code>的例子</div><div·class="example-contents"><pre·class="programlisting">#include·<sys/kernel.h> |
| |
1254 | void·foo_cleanup(void·*unused) | 1254 | void·foo_cleanup(void·*unused) |
1255 | { | 1255 | { |
1256 | ········foo_kill(); | 1256 | ········foo_kill(); |
1257 | } | 1257 | } |
1258 | SYSUNINIT(foobar,·SI_SUB_FOO,·SI_ORDER_FOO,·foo_cleanup,·NULL); | 1258 | SYSUNINIT(foobar,·SI_SUB_FOO,·SI_ORDER_FOO,·foo_cleanup,·NULL); |
Offset 2360, 23 lines modified | Offset 2360, 23 lines modified |
2360 | ·········此时页被从磁盘中载入。</p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">Intel等厂商的CPU工作在保护模式时,可用来实现虚拟内存。 | 2360 | ·········此时页被从磁盘中载入。</p><div·xmlns=""·class="tip"><h3·class="admontitle">译者注:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">Intel等厂商的CPU工作在保护模式时,可用来实现虚拟内存。 |
2361 | ·········当寻址的地址空间对应着真实内存时,则正常读写; | 2361 | ·········当寻址的地址空间对应着真实内存时,则正常读写; |
2362 | ·········当寻址的地址空间没有对应的真实内存时,CPU会产生一个“错误”, | 2362 | ·········当寻址的地址空间没有对应的真实内存时,CPU会产生一个“错误”, |
2363 | ·········通知操作系统与磁盘等设备进行交换,读寻址则调入存储内容, | 2363 | ·········通知操作系统与磁盘等设备进行交换,读寻址则调入存储内容, |
2364 | ·········写寻址则写出存储内容。这个“错误” | 2364 | ·········写寻址则写出存储内容。这个“错误” |
2365 | ·········并非操作系统或应用程序开发人员犯下的错误, | 2365 | ·········并非操作系统或应用程序开发人员犯下的错误, |
2366 | ·········尽管在CPU硬件实现中这与应用程序或操作系统内核崩溃的错误的发生机制相同。 | 2366 | ·········尽管在CPU硬件实现中这与应用程序或操作系统内核崩溃的错误的发生机制相同。 |
2367 | ·········参见Intel的CPU保护模式开发手册。</p></div><a·id="idp67001784"·class="indexterm"></a><p>FreeBSD动态的调整页队列,试图将各个队列中的页数维护在一个适当的比例上, | 2367 | ·········参见Intel的CPU保护模式开发手册。</p></div><a·id="idp67005880"·class="indexterm"></a><p>FreeBSD动态的调整页队列,试图将各个队列中的页数维护在一个适当的比例上, |
2368 | ········同时管理程序崩溃的已清理和未清理页。重新平衡的比例数值决定于系统内存的负担。 | 2368 | ········同时管理程序崩溃的已清理和未清理页。重新平衡的比例数值决定于系统内存的负担。 |
2369 | ········这种重新平衡由pageout守护进程实现,包括清理未清理页(与他们的后备存储同步)、 | 2369 | ········这种重新平衡由pageout守护进程实现,包括清理未清理页(与他们的后备存储同步)、 |
2370 | ········监视页被引用的活跃程度 | 2370 | ········监视页被引用的活跃程度 |
2371 | ········(重置它们在LRU队列中的位置或在不同活跃程度的页队列间移动)、 | 2371 | ········(重置它们在LRU队列中的位置或在不同活跃程度的页队列间移动)、 |
2372 | ········当比例不平衡时在队列间迁移页,如此等等。 | 2372 | ········当比例不平衡时在队列间迁移页,如此等等。 |
2373 | ········FreeBSD的VM系统会将重激活页而产生的错误频率调低到一个合理的数值, | 2373 | ········FreeBSD的VM系统会将重激活页而产生的错误频率调低到一个合理的数值, |
2374 | ········由此确定某一页活跃/闲置的实际程度。 | 2374 | ········由此确定某一页活跃/闲置的实际程度。 |
2375 | ········这可以为更好的决定何时清理/分配一个页做出决策。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="vm-cache"></a>7.2. 统一的缓存信息结构体──<code·class="literal">vm_object_t</code></h2></div></div></div><a·id="idp67003832"·class="indexterm"></a><a·id="idp67004344"·class="indexterm"></a><p>FreeBSD实现了统一的<span·class="quote">“<span·class="quote">虚拟内存对象</span>”</span>(VM对象)的设计思想。 | 2375 | ········这可以为更好的决定何时清理/分配一个页做出决策。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="vm-cache"></a>7.2. 统一的缓存信息结构体──<code·class="literal">vm_object_t</code></h2></div></div></div><a·id="idp67007928"·class="indexterm"></a><a·id="idp67008440"·class="indexterm"></a><p>FreeBSD实现了统一的<span·class="quote">“<span·class="quote">虚拟内存对象</span>”</span>(VM对象)的设计思想。 |
2376 | ··········VM对象可以与各种类型的内存使用方式相结合──直接使用(unbacked)、 | 2376 | ··········VM对象可以与各种类型的内存使用方式相结合──直接使用(unbacked)、 |
2377 | ··········交换(swap)、物理设备、文件。 | 2377 | ··········交换(swap)、物理设备、文件。 |
2378 | ··········由于文件系统使用相同的VM对象管理核内数据──文件的缓存, | 2378 | ··········由于文件系统使用相同的VM对象管理核内数据──文件的缓存, |
2379 | ··········所以这些缓存的结构也是统一的。</p><p>VM对象可以被<span·class="emphasis"><em>影复制</em></span>(shadowed)。 | 2379 | ··········所以这些缓存的结构也是统一的。</p><p>VM对象可以被<span·class="emphasis"><em>影复制</em></span>(shadowed)。 |
2380 | ·········它们可以被堆放到其它类别VM对象堆栈的顶端。例如,可以有一个交换VM对象, | 2380 | ·········它们可以被堆放到其它类别VM对象堆栈的顶端。例如,可以有一个交换VM对象, |
2381 | ·········放置在文件VM对象堆栈的顶端,以实现MAP_PRIVATE的mmap()操作。 | 2381 | ·········放置在文件VM对象堆栈的顶端,以实现MAP_PRIVATE的mmap()操作。 |
2382 | ·········这样的入栈操作也可以用来实现各种各样的共享特性, | 2382 | ·········这样的入栈操作也可以用来实现各种各样的共享特性, |
Offset 2441, 15 lines modified | Offset 2441, 15 lines modified |
2441 | ··········你可以在内核配置文件中用<code·class="literal">makeoptions</code> | 2441 | ··········你可以在内核配置文件中用<code·class="literal">makeoptions</code> |
2442 | ··········指定排错(debugging)和优化标志。注意,你一般不应使用<code·class="option">-g</code>, | 2442 | ··········指定排错(debugging)和优化标志。注意,你一般不应使用<code·class="option">-g</code>, |
2443 | ··········除非你能够应付由此产生的大内核(典型的是7MB或更多)。</p><pre·class="programlisting">makeoptions······DEBUG="-g" | 2443 | ··········除非你能够应付由此产生的大内核(典型的是7MB或更多)。</p><pre·class="programlisting">makeoptions······DEBUG="-g" |
2444 | makeoptions······COPTFLAGS="-O·-pipe"</pre><p>Sysctl提供了在运行时调整内核的方式。你通常不需要指定任何sysctl变量, | 2444 | makeoptions······COPTFLAGS="-O·-pipe"</pre><p>Sysctl提供了在运行时调整内核的方式。你通常不需要指定任何sysctl变量, |
2445 | ··········尤其是与VM相关的那些变量。</p><p>运行时VM和系统调整的影响相对直接一些。 | 2445 | ··········尤其是与VM相关的那些变量。</p><p>运行时VM和系统调整的影响相对直接一些。 |
2446 | ··········首先,应当尽可能在UFS/FFS文件系统上使用Soft·Updates。 | 2446 | ··········首先,应当尽可能在UFS/FFS文件系统上使用Soft·Updates。 |
2447 | ··········在<code·class="filename">/usr/src/sys/ufs/ffs/README.softupdates</code> | 2447 | ··········在<code·class="filename">/usr/src/sys/ufs/ffs/README.softupdates</code> |
2448 | ··········里有关于如何配置的指示。</p><a·id="idp67047992"·class="indexterm"></a><p>其次,应当配置足够多的交换空间。 | 2448 | ··········里有关于如何配置的指示。</p><a·id="idp67052088"·class="indexterm"></a><p>其次,应当配置足够多的交换空间。 |
2449 | ··············你应当在每个物理磁盘上配置一个交换分区,最多4个, | 2449 | ··············你应当在每个物理磁盘上配置一个交换分区,最多4个, |
2450 | ··········甚至在你的<span·class="quote">“<span·class="quote">工作</span>”</span>磁盘上。你应当有至少2倍于主内存的交换空间; | 2450 | ··········甚至在你的<span·class="quote">“<span·class="quote">工作</span>”</span>磁盘上。你应当有至少2倍于主内存的交换空间; |
2451 | ··········假如你没有足够内存的话,交换分区还应更多。 | 2451 | ··········假如你没有足够内存的话,交换分区还应更多。 |
2452 | ··········你也应当按照你期望中的最大内存配置决定交换分区的大小, | 2452 | ··········你也应当按照你期望中的最大内存配置决定交换分区的大小, |
2453 | ··········这样以后就不再需要重新给磁盘分区了。 | 2453 | ··········这样以后就不再需要重新给磁盘分区了。 |
2454 | ··········如果你处理系统崩溃后的内存倾倒(crash·dump), | 2454 | ··········如果你处理系统崩溃后的内存倾倒(crash·dump), |
2455 | ··········第一个交换分区必须至少与主内存一样大, | 2455 | ··········第一个交换分区必须至少与主内存一样大, |
Offset 2464, 15 lines modified | Offset 2464, 15 lines modified |
2464 | ······但我们会逐渐为其充实内容。·关于这份文档的更新和建议, | 2464 | ······但我们会逐渐为其充实内容。·关于这份文档的更新和建议, |
2465 | ······请发给文档编辑。</p><a·id="idp67064248"·class="indexterm"></a><p>SMPng·的目标是使内核能够并发执行。·基本上, | 2465 | ······请发给文档编辑。</p><a·id="idp67064248"·class="indexterm"></a><p>SMPng·的目标是使内核能够并发执行。·基本上, |
2466 | ······内核是一个很大而复杂的程序。·要让内核能够多线程地执行, | 2466 | ······内核是一个很大而复杂的程序。·要让内核能够多线程地执行, |
2467 | ······我们需要使用某些其它多线程程序在实现时所用到的工具, | 2467 | ······我们需要使用某些其它多线程程序在实现时所用到的工具, |
2468 | ······这包括互斥体(mutex)、·共享/排他锁(shared/exclusive·lock)、 | 2468 | ······这包括互斥体(mutex)、·共享/排他锁(shared/exclusive·lock)、 |
2469 | ······信号量(semaphores)·和条件变量(condition·variable)。 | 2469 | ······信号量(semaphores)·和条件变量(condition·variable)。 |
2470 | ······如果希望了解它们以及其它·SMP·术语, | 2470 | ······如果希望了解它们以及其它·SMP·术语, |
2471 | ······请参阅本文的·<a·class="xref"·href="#smp-glossary"·title="术语表">术语表</a>·一节。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="smp-lock-fundamentals"></a>8.2. 基本工具与上锁的基础知识</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67066424"></a>8.2.1. 原子操作指令和内存栅</h3></div></div></div><a·id="idp67067064"·class="indexterm"></a><a·id="idp67067576"·class="indexterm"></a><p>关于内存栅和原子操作指令已经有很多介绍材料, | 2471 | ······请参阅本文的·<a·class="xref"·href="#smp-glossary"·title="术语表">术语表</a>·一节。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="smp-lock-fundamentals"></a>8.2. 基本工具与上锁的基础知识</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67066424"></a>8.2.1. 原子操作指令和内存栅</h3></div></div></div><a·id="idp67087544"·class="indexterm"></a><a·id="idp67088056"·class="indexterm"></a><p>关于内存栅和原子操作指令已经有很多介绍材料, |
2472 | » 因此这一节并不打算对其进行详尽的介绍。·简而言之,·如果有对某一变量上写锁, | 2472 | » 因此这一节并不打算对其进行详尽的介绍。·简而言之,·如果有对某一变量上写锁, |
2473 | » 就不能在不获得相应的锁时对其进行读取操作。·也就是说, | 2473 | » 就不能在不获得相应的锁时对其进行读取操作。·也就是说, |
2474 | » 内存栅的作用在于保证内存操作的相对顺序,·但并不保证内存操作的严格时序。 | 2474 | » 内存栅的作用在于保证内存操作的相对顺序,·但并不保证内存操作的严格时序。 |
2475 | » 换言之,·内存栅并不保证·CPU·将本地快取缓存或存储缓冲的内容刷写回内存, | 2475 | » 换言之,·内存栅并不保证·CPU·将本地快取缓存或存储缓冲的内容刷写回内存, |
2476 | » 而是在锁释放时确保其所保护的数据,·对于能看到刚释放的那个锁的·CPU | 2476 | » 而是在锁释放时确保其所保护的数据,·对于能看到刚释放的那个锁的·CPU |
2477 | » 或设备可见。·持有内存栅的·CPU | 2477 | » 或设备可见。·持有内存栅的·CPU |
2478 | » 可以在其快取缓存或存储缓冲中将数据保持其所希望的、·任意长的时间, | 2478 | » 可以在其快取缓存或存储缓冲中将数据保持其所希望的、·任意长的时间, |
Offset 2490, 51 lines modified | Offset 2490, 51 lines modified |
2490 | » 也可能在我们进行决策的过程中发生变化。·因此,·当执行 | 2490 | » 也可能在我们进行决策的过程中发生变化。·因此,·当执行 |
2491 | » <code·class="function">atomic_set</code>·时,·最终可能会对另一值进行置位, | 2491 | » <code·class="function">atomic_set</code>·时,·最终可能会对另一值进行置位, |
2492 | » 而不是我们进行决策的那一个。·这就必须通过 | 2492 | » 而不是我们进行决策的那一个。·这就必须通过 |
2493 | » <code·class="function">atomic_cmpset</code>·来保证只有在我们的决策依据是最新的时, | 2493 | » <code·class="function">atomic_cmpset</code>·来保证只有在我们的决策依据是最新的时, |
2494 | » 才对相应的变量进行置位。</p><p>最后,·原子操作只允许一次更新或读一个内存单元。 | 2494 | » 才对相应的变量进行置位。</p><p>最后,·原子操作只允许一次更新或读一个内存单元。 |
2495 | » 需要原子地更新多个单元时,·就必须使用锁来代替它了。 | 2495 | » 需要原子地更新多个单元时,·就必须使用锁来代替它了。 |
2496 | » 例如,·如果需要更新两个相互关联的计数器时, | 2496 | » 例如,·如果需要更新两个相互关联的计数器时, |
2497 | » 就必须使用锁,·而不是两次单独的原子操作了。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67084472"></a>8.2.2. 读锁与写锁</h3></div></div></div><a·id="idp67085112"·class="indexterm"></a><a·id="idp67085624"·class="indexterm"></a><p>读锁并不需要像写锁那样强。·这两种类型的锁, | 2497 | » 就必须使用锁,·而不是两次单独的原子操作了。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67092664"></a>8.2.2. 读锁与写锁</h3></div></div></div><a·id="idp67093304"·class="indexterm"></a><a·id="idp67093816"·class="indexterm"></a><p>读锁并不需要像写锁那样强。·这两种类型的锁, |
2498 | » 都需要确保通过它们访问的不是过时的数据。·然而, | 2498 | » 都需要确保通过它们访问的不是过时的数据。·然而, |
2499 | » 只有写操作必须是排他的,·而多个线程则可以安全地读同一变量的值。 | 2499 | » 只有写操作必须是排他的,·而多个线程则可以安全地读同一变量的值。 |
2500 | » 使用不同类型的锁用于读和写操作有许多各自不同的实现方式。</p><p>第一种方法是用·sx·锁,·它可以用于实现写时使用的排他锁, | 2500 | » 使用不同类型的锁用于读和写操作有许多各自不同的实现方式。</p><p>第一种方法是用·sx·锁,·它可以用于实现写时使用的排他锁, |
2501 | » 而读时则作为共享锁。·这种方法十分简单明了。</p><p>第二种方法则略显晦涩。·可以用多个锁来保护同一数据元。 | 2501 | » 而读时则作为共享锁。·这种方法十分简单明了。</p><p>第二种方法则略显晦涩。·可以用多个锁来保护同一数据元。 |
2502 | » 读时,·只需锁其中的一个读锁即可。·然而,·如果要写数据的话, | 2502 | » 读时,·只需锁其中的一个读锁即可。·然而,·如果要写数据的话, |
2503 | » 则需要首先上所有的写锁。·这会大大提高写操作的代价, | 2503 | » 则需要首先上所有的写锁。·这会大大提高写操作的代价, |
2504 | » 但当可能以多种方式访问数据时却可能非常有用。·例如, | 2504 | » 但当可能以多种方式访问数据时却可能非常有用。·例如, |
2505 | » 父进程指针是同时受 | 2505 | » 父进程指针是同时受 |
2506 | » <code·class="varname">proctree_lock</code>·sx·锁和进程·mutex·保护的。 | 2506 | » <code·class="varname">proctree_lock</code>·sx·锁和进程·mutex·保护的。 |
2507 | » 在只希望检查已锁进程的父进程时,·用·proc·锁更为方便。 | 2507 | » 在只希望检查已锁进程的父进程时,·用·proc·锁更为方便。 |
2508 | » 但是,·其它一些地方,·例如 | 2508 | » 但是,·其它一些地方,·例如 |
2509 | » <code·class="function">inferior</code>·这类需要通过父指针在进程树上进行搜索, | 2509 | » <code·class="function">inferior</code>·这类需要通过父指针在进程树上进行搜索, |
2510 | » 并对每个进程上锁的地方就不能这样做了, | 2510 | » 并对每个进程上锁的地方就不能这样做了, |
2511 | » 否则,·将无法保证在对我们所获得的结果执行操作时, | 2511 | » 否则,·将无法保证在对我们所获得的结果执行操作时, |
2512 | » 之前检查时的状况依旧有效。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67088184"></a>8.2.3. 上锁状态和结果</h3></div></div></div><p>如果您需要使用锁来保持所检查变量的状态,·并据此执行某些操作时, | 2512 | » 之前检查时的状况依旧有效。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67096376"></a>8.2.3. 上锁状态和结果</h3></div></div></div><p>如果您需要使用锁来保持所检查变量的状态,·并据此执行某些操作时, |
2513 | » 是不能仅仅在读变量之前对其上锁,·并在执行操作之前解锁的。 | 2513 | » 是不能仅仅在读变量之前对其上锁,·并在执行操作之前解锁的。 |
2514 | » 过早解锁将使变量再次可变,·这可能会导致之前所做的决策失效。 | 2514 | » 过早解锁将使变量再次可变,·这可能会导致之前所做的决策失效。 |
2515 | » 因此,·在所做检测引发的动作结束之前,·必须继续保持上锁状态。</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="smp-design"></a>8.3. 架构与设计概览</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67090232"></a>8.3.1. 对中断的处理</h3></div></div></div><a·id="idp67090872"·class="indexterm"></a><p>与许多其它多线程·<span·class="trademark">UNIX</span>®·内核所采取的模式类似,·FreeBSD | 2515 | » 因此,·在所做检测引发的动作结束之前,·必须继续保持上锁状态。</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="smp-design"></a>8.3. 架构与设计概览</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67098424"></a>8.3.1. 对中断的处理</h3></div></div></div><a·id="idp67099064"·class="indexterm"></a><p>与许多其它多线程·<span·class="trademark">UNIX</span>®·内核所采取的模式类似,·FreeBSD |
2516 | » 会赋予中断处理程序独立的线程上下文, | 2516 | » 会赋予中断处理程序独立的线程上下文, |
2517 | » 这样做能够让中断线程在遇到锁时阻塞。·但为了避免不必要的延迟, | 2517 | » 这样做能够让中断线程在遇到锁时阻塞。·但为了避免不必要的延迟, |
2518 | » 中断线程在内核中,·是以实时线程的优先级运行的。·因此, | 2518 | » 中断线程在内核中,·是以实时线程的优先级运行的。·因此, |
2519 | » 中断处理程序不应执行过久,·以免饿死其它内核线程。·此外, | 2519 | » 中断处理程序不应执行过久,·以免饿死其它内核线程。·此外, |
2520 | » 由于多个处理程序可以分享同一中断线程,·中断处理程序不应休眠, | 2520 | » 由于多个处理程序可以分享同一中断线程,·中断处理程序不应休眠, |
2521 | » 或使用可能导致休眠的锁,·以避免将其它中断处理程序饿死。</p><a·id="idp67092280"·class="indexterm"></a><p>目前在·FreeBSD·中的中断线程是指重量级中断线程。 | 2521 | » 或使用可能导致休眠的锁,·以避免将其它中断处理程序饿死。</p><a·id="idp67100472"·class="indexterm"></a><p>目前在·FreeBSD·中的中断线程是指重量级中断线程。 |
2522 | » 这样称呼它们的原因在于,·转到中断线程需要执行一次完整的上下文切换操作。 | 2522 | » 这样称呼它们的原因在于,·转到中断线程需要执行一次完整的上下文切换操作。 |
2523 | » 在最初的实现中,·内核不允许抢占,·因此中断在打断内核线程之前, | 2523 | » 在最初的实现中,·内核不允许抢占,·因此中断在打断内核线程之前, |
2524 | » 必须等待内核线程阻塞或返回用户态之后才能执行。</p><a·id="idp67093176"·class="indexterm"></a><a·id="idp67093688"·class="indexterm"></a><p>为了解决响应时间问题,·FreeBSD·内核现在采用了抢占式调度策略。 | 2524 | » 必须等待内核线程阻塞或返回用户态之后才能执行。</p><a·id="idp67101368"·class="indexterm"></a><a·id="idp67101880"·class="indexterm"></a><p>为了解决响应时间问题,·FreeBSD·内核现在采用了抢占式调度策略。 |
2525 | » 目前,·只有释放休眠·mutex·或发生中断时才能抢断内核线程, | 2525 | » 目前,·只有释放休眠·mutex·或发生中断时才能抢断内核线程, |
2526 | » 但最终目标是在·FreeBSD·上实现下面所描述的全抢占式调度策略。</p><p>并非所有的中断处理程序都在独立的线程上下文中执行。 | 2526 | » 但最终目标是在·FreeBSD·上实现下面所描述的全抢占式调度策略。</p><p>并非所有的中断处理程序都在独立的线程上下文中执行。 |
2527 | » 相反,·某些处理程序会直接在主中断上下文中执行。·这些中断处理程序, | 2527 | » 相反,·某些处理程序会直接在主中断上下文中执行。·这些中断处理程序, |
2528 | » 现在被错误地命名为 | 2528 | » 现在被错误地命名为 |
2529 | » <span·class="quote">“<span·class="quote">快速</span>”</span>·中断处理程序,·因为早期版本的内核中使用了 | 2529 | » <span·class="quote">“<span·class="quote">快速</span>”</span>·中断处理程序,·因为早期版本的内核中使用了 |
2530 | » <code·class="constant">INTR_FAST</code>·标志来标记这些处理程序。 | 2530 | » <code·class="constant">INTR_FAST</code>·标志来标记这些处理程序。 |
2531 | » 目前只有时钟中断和串口·I/O·设备中断采用这一类型。 | 2531 | » 目前只有时钟中断和串口·I/O·设备中断采用这一类型。 |
2532 | » 由于这些处理程序没有独立的上下文,·因而它们都不能获得阻塞性锁, | 2532 | » 由于这些处理程序没有独立的上下文,·因而它们都不能获得阻塞性锁, |
2533 | » 因此也就只能使用自旋·mutex。</p><a·id="idp67095736"·class="indexterm"></a><p>最后,·还有一种称为轻量级上下文切换的优化, | 2533 | » 因此也就只能使用自旋·mutex。</p><a·id="idp67103928"·class="indexterm"></a><p>最后,·还有一种称为轻量级上下文切换的优化, |
2534 | » 可以在·MD·代码中使用。·因为中断线程都是在内核上下文中执行的, | 2534 | » 可以在·MD·代码中使用。·因为中断线程都是在内核上下文中执行的, |
2535 | » 所以它可以借用任意进程的·vmspace·(虚拟内存地址空间)。·因此, | 2535 | » 所以它可以借用任意进程的·vmspace·(虚拟内存地址空间)。·因此, |
2536 | » 在轻量级上下文切换中,·切换到中断线程并不切换对应的·vmspace, | 2536 | » 在轻量级上下文切换中,·切换到中断线程并不切换对应的·vmspace, |
2537 | » 而是借用被中断线程的·vmspace。·为确保被中断线程的·vmspace | 2537 | » 而是借用被中断线程的·vmspace。·为确保被中断线程的·vmspace |
2538 | » 不在中断处理过程中消失,·被中断线程在中断线程不再借用其·vmspace | 2538 | » 不在中断处理过程中消失,·被中断线程在中断线程不再借用其·vmspace |
2539 | » 之前是不允许执行的。·刚才提到的情况可能在中断线程阻塞或完成时发生。 | 2539 | » 之前是不允许执行的。·刚才提到的情况可能在中断线程阻塞或完成时发生。 |
2540 | » 如果中断线程发生阻塞,·则它再次进入可运行状态时将使用自己的上下文, | 2540 | » 如果中断线程发生阻塞,·则它再次进入可运行状态时将使用自己的上下文, |
Offset 2545, 53 lines modified | Offset 2545, 53 lines modified |
2545 | » 而这种阻塞将进而需要线程修正。·另外,·Mike·Smith | 2545 | » 而这种阻塞将进而需要线程修正。·另外,·Mike·Smith |
2546 | » 提议采用另一种方式来处理中断线程:</p><div·class="orderedlist"><ol·class="orderedlist"·type="1"><li·class="listitem"><p>每个中断处理程序分为两部分,·一个在主中断上下文中运行的主体 | 2546 | » 提议采用另一种方式来处理中断线程:</p><div·class="orderedlist"><ol·class="orderedlist"·type="1"><li·class="listitem"><p>每个中断处理程序分为两部分,·一个在主中断上下文中运行的主体 |
2547 | » ····(predicate)·和一个在自己的线程上下文中执行的处理程序·(handler)。</p></li><li·class="listitem"><p>如果中断处理程序拥有主体,·则当触发中断时,·执行该主体。 | 2547 | » ····(predicate)·和一个在自己的线程上下文中执行的处理程序·(handler)。</p></li><li·class="listitem"><p>如果中断处理程序拥有主体,·则当触发中断时,·执行该主体。 |
2548 | » ····如果主体返回真,·则认为该中断被处理完毕,·内核从中断返回。 | 2548 | » ····如果主体返回真,·则认为该中断被处理完毕,·内核从中断返回。 |
2549 | » ····如果主体返回假,·或者中断没有主体,·则调度运行线程式处理程序。</p></li></ol></div><p>在这一模式中适当地采用轻量级上下文切换可能是非常复杂的。 | 2549 | » ····如果主体返回假,·或者中断没有主体,·则调度运行线程式处理程序。</p></li></ol></div><p>在这一模式中适当地采用轻量级上下文切换可能是非常复杂的。 |
2550 | » 因为我们可能会希望在未来改变这一模式,·因此现在最好的方案, | 2550 | » 因为我们可能会希望在未来改变这一模式,·因此现在最好的方案, |
2551 | » 应该是暂时推迟在轻量级上下文切换之上的工作, | 2551 | » 应该是暂时推迟在轻量级上下文切换之上的工作, |
2552 | » 以便进一步完善中断处理架构,·随后再考察轻量级上下文切换是否适用。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67103544"></a>8.3.2. 内核抢占与临界区</h3></div></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67104184"></a>8.3.2.1. 内核抢占简介</h4></div></div></div><p>内核抢占的概念很简单,·其基本思想是·CPU·总应执行优先级最高的工作。 | 2552 | » 以便进一步完善中断处理架构,·随后再考察轻量级上下文切换是否适用。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67107640"></a>8.3.2. 内核抢占与临界区</h3></div></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67108280"></a>8.3.2.1. 内核抢占简介</h4></div></div></div><p>内核抢占的概念很简单,·其基本思想是·CPU·总应执行优先级最高的工作。 |
2553 | » ··当然,·至少在理想情况下是这样。·有些时候, | 2553 | » ··当然,·至少在理想情况下是这样。·有些时候, |
2554 | » ··达成这一理想的代价会十分高昂,·以至于在这些情况下抢占会得不偿失。</p><p>实现完全的内核抢占十分简单:·在调度将要执行的线程并放入运行队列时, | 2554 | » ··达成这一理想的代价会十分高昂,·以至于在这些情况下抢占会得不偿失。</p><p>实现完全的内核抢占十分简单:·在调度将要执行的线程并放入运行队列时, |
2555 | » ··检查它的优先级是否高于目前正在执行的线程。·如果是这样的话, | 2555 | » ··检查它的优先级是否高于目前正在执行的线程。·如果是这样的话, |
2556 | » ··执行一次上下文切换并立即开始执行该线程。</p><p>尽管锁能够在抢占时保护多数数据,·但内核并不是可以安全地处处抢占的。 | 2556 | » ··执行一次上下文切换并立即开始执行该线程。</p><p>尽管锁能够在抢占时保护多数数据,·但内核并不是可以安全地处处抢占的。 |
2557 | » ··例如,·如果持有自旋·mutex·的线程被抢占,·而新线程也尝试获得同一自旋 | 2557 | » ··例如,·如果持有自旋·mutex·的线程被抢占,·而新线程也尝试获得同一自旋 |
2558 | » ··mutex,·新线程就可能一直自旋下去, | 2558 | » ··mutex,·新线程就可能一直自旋下去, |
2559 | » ··因为被中断的线程可能永远没有机会运行了。·此外,·某些代码,·例如在·Alpha·上的 | 2559 | » ··因为被中断的线程可能永远没有机会运行了。·此外,·某些代码,·例如在·Alpha·上的 |
2560 | » ··<code·class="function">exec</code>·对进程地址空间编号进行赋值的代码也不能被抢断, | 2560 | » ··<code·class="function">exec</code>·对进程地址空间编号进行赋值的代码也不能被抢断, |
2561 | » ··因为它被用来支持实际的上下文切换操作。·在这些代码段中, | 2561 | » ··因为它被用来支持实际的上下文切换操作。·在这些代码段中, |
2562 | » ··会通过使用临界区来临时禁用抢占。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67106488"></a>8.3.2.2. 临界区</h4></div></div></div><a·id="idp67107128"·class="indexterm"></a><p>临界区·API·的责任是避免在临界区内发生上下文切换。 | 2562 | » ··会通过使用临界区来临时禁用抢占。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67110584"></a>8.3.2.2. 临界区</h4></div></div></div><a·id="idp67111224"·class="indexterm"></a><p>临界区·API·的责任是避免在临界区内发生上下文切换。 |
2563 | » ··对于完全抢占式内核而言,·除了当前线程之外的其它线程的每个 | 2563 | » ··对于完全抢占式内核而言,·除了当前线程之外的其它线程的每个 |
2564 | » ··<code·class="function">setrunqueue</code>·都是抢断点。 | 2564 | » ··<code·class="function">setrunqueue</code>·都是抢断点。 |
2565 | » ··<code·class="function">critical_enter</code>·的一种实现方式是设置一线程私有标记, | 2565 | » ··<code·class="function">critical_enter</code>·的一种实现方式是设置一线程私有标记, |
2566 | » ··并由其对应方清除。·如果调用 | 2566 | » ··并由其对应方清除。·如果调用 |
2567 | » ··<code·class="function">setrunqueue</code>·时设置了这个标志, | 2567 | » ··<code·class="function">setrunqueue</code>·时设置了这个标志, |
2568 | » ··则无论新线程和当前线程相比其优先级高低,·都不会发生抢占。 | 2568 | » ··则无论新线程和当前线程相比其优先级高低,·都不会发生抢占。 |
2569 | » ··然而,·由于临界区会在自旋·mutex·中用于避免上下文切换, | 2569 | » ··然而,·由于临界区会在自旋·mutex·中用于避免上下文切换, |
2570 | » ··而且能够同时获得多个自旋·mutex,·因此临界区·API·必须支持嵌套。 | 2570 | » ··而且能够同时获得多个自旋·mutex,·因此临界区·API·必须支持嵌套。 |
2571 | » ··由于这个原因,·目前的实现中采用了嵌套计数, | 2571 | » ··由于这个原因,·目前的实现中采用了嵌套计数, |
2572 | » ··而不仅仅是单个的线程标志。</p><p>为了尽可能缩短响应时间,·在临界区中的抢占被推迟, | 2572 | » ··而不仅仅是单个的线程标志。</p><p>为了尽可能缩短响应时间,·在临界区中的抢占被推迟, |
2573 | » ··而不是直接丢弃。·如果线程应被抢断,·并被置为可运行, | 2573 | » ··而不是直接丢弃。·如果线程应被抢断,·并被置为可运行, |
2574 | » ··而当前线程处于临界区,·则会设置一线程私有标志, | 2574 | » ··而当前线程处于临界区,·则会设置一线程私有标志, |
2575 | » ··表示有一个尚未进行的抢断操作。·当最外层临界区退出时, | 2575 | » ··表示有一个尚未进行的抢断操作。·当最外层临界区退出时, |
2576 | » ··会检查这一标志,·如果它被置位,·则当前线程会被抢断, | 2576 | » ··会检查这一标志,·如果它被置位,·则当前线程会被抢断, |
2577 | » ··以允许更高优先级的线程开始运行。</p><a·id="idp67109560"·class="indexterm"></a><a·id="idp67110072"·class="indexterm"></a><p>中断会引发一个和自旋·mutex·有关的问题。 | 2577 | » ··以允许更高优先级的线程开始运行。</p><a·id="idp67125944"·class="indexterm"></a><a·id="idp67126456"·class="indexterm"></a><p>中断会引发一个和自旋·mutex·有关的问题。 |
2578 | » ··如果低级中断处理程序需要锁,·它就不能中断任何需要该锁的代码, | 2578 | » ··如果低级中断处理程序需要锁,·它就不能中断任何需要该锁的代码, |
2579 | » ··以避免可能发生的损坏数据结构的情况。·目前,这一机制是透过临界区·API | 2579 | » ··以避免可能发生的损坏数据结构的情况。·目前,这一机制是透过临界区·API |
2580 | » ··以·<code·class="function">cpu_critical_enter</code>·和 | 2580 | » ··以·<code·class="function">cpu_critical_enter</code>·和 |
2581 | » ··<code·class="function">cpu_critical_exit</code>·函数的形式实现的。 | 2581 | » ··<code·class="function">cpu_critical_exit</code>·函数的形式实现的。 |
2582 | » ··目前这一·API·会在所有·FreeBSD | 2582 | » ··目前这一·API·会在所有·FreeBSD |
2583 | » ··所支持的平台上禁用和重新启用中断。·这种方法并不是最优的, | 2583 | » ··所支持的平台上禁用和重新启用中断。·这种方法并不是最优的, |
2584 | » ··但它更易理解,·也更容易正确地实现。·理论上,·这一辅助·API | 2584 | » ··但它更易理解,·也更容易正确地实现。·理论上,·这一辅助·API |
2585 | » ··只需要配合在主中断上下文中的自旋·mutex·使用。·然而, | 2585 | » ··只需要配合在主中断上下文中的自旋·mutex·使用。·然而, |
2586 | » ··为了让代码更为简单,·它被用在了全部自旋·mutex, | 2586 | » ··为了让代码更为简单,·它被用在了全部自旋·mutex, |
2587 | » ··甚至包括所有临界区上。·将其从·MI·API·中剥离出来放入·MD·API, | 2587 | » ··甚至包括所有临界区上。·将其从·MI·API·中剥离出来放入·MD·API, |
2588 | » ··并只在需要使用它的·MI·API·的自旋·mutex·实现中使用可能会有更好的效果。 | 2588 | » ··并只在需要使用它的·MI·API·的自旋·mutex·实现中使用可能会有更好的效果。 |
2589 | » ··如果我们最终采用了这种实现方式,·则·MD·API | 2589 | » ··如果我们最终采用了这种实现方式,·则·MD·API |
2590 | » ··可能需要改名,·以彰显其为一单独·API·这一事实。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67132600"></a>8.3.2.3. 设计折衷</h4></div></div></div><p>如前面提到的,·当完全抢占并非总能提供最佳性能时, | 2590 | » ··可能需要改名,·以彰显其为一单独·API·这一事实。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67148984"></a>8.3.2.3. 设计折衷</h4></div></div></div><p>如前面提到的,·当完全抢占并非总能提供最佳性能时, |
2591 | » ··采取了一些折衷的措施。</p><p>第一处折衷是,·抢占代码并不考虑其它·CPU·的存在。 | 2591 | » ··采取了一些折衷的措施。</p><p>第一处折衷是,·抢占代码并不考虑其它·CPU·的存在。 |
2592 | » ··假设我们有两个·CPU,·A | 2592 | » ··假设我们有两个·CPU,·A |
2593 | » ··和·B,·其中·A·上线程的优先级为·4, | 2593 | » ··和·B,·其中·A·上线程的优先级为·4, |
2594 | » ··而·B·上线程的优先级是·2。·如果·CPU·B·令一优先级为·1 | 2594 | » ··而·B·上线程的优先级是·2。·如果·CPU·B·令一优先级为·1 |
2595 | » ··的线程进入可运行状态,·则理论上,·我们希望·CPU·A·切换至这一新线程, | 2595 | » ··的线程进入可运行状态,·则理论上,·我们希望·CPU·A·切换至这一新线程, |
2596 | » ··这样就有两个优先级最高的线程在运行了。·然而,·确定哪个 | 2596 | » ··这样就有两个优先级最高的线程在运行了。·然而,·确定哪个 |
2597 | » ··CPU·在抢占时更合适,·并通过·IPI·向那个·CPU·发出信号, | 2597 | » ··CPU·在抢占时更合适,·并通过·IPI·向那个·CPU·发出信号, |
Offset 2607, 23 lines modified | Offset 2607, 23 lines modified |
2607 | » ··当内核返回到被抢断的线程时,·它又需要重新填充之前丢失的快取缓存信息。 | 2607 | » ··当内核返回到被抢断的线程时,·它又需要重新填充之前丢失的快取缓存信息。 |
2608 | » ··此外,·如果内核能够将对将阻塞或返回用户态的那个线程的抢断延迟到这之后的话, | 2608 | » ··此外,·如果内核能够将对将阻塞或返回用户态的那个线程的抢断延迟到这之后的话, |
2609 | » ··还能够免去两次额外的上下文切换。·因此,·默认情况下, | 2609 | » ··还能够免去两次额外的上下文切换。·因此,·默认情况下, |
2610 | » ··只有在优先级较高的线程是实时线程时,·抢占代码才会立即执行抢断操作。</p><p>启用针对所有内核线程的完全抢占对于调试非常有帮助, | 2610 | » ··只有在优先级较高的线程是实时线程时,·抢占代码才会立即执行抢断操作。</p><p>启用针对所有内核线程的完全抢占对于调试非常有帮助, |
2611 | » ··因为它会暴露出更多的竞态条件·(race·conditions)。 | 2611 | » ··因为它会暴露出更多的竞态条件·(race·conditions)。 |
2612 | » ··在难以模拟这些竞态条件的单处理器系统中,·这显得尤其有用。 | 2612 | » ··在难以模拟这些竞态条件的单处理器系统中,·这显得尤其有用。 |
2613 | » ··因此,·我们提供了内核选项·<code·class="literal">FULL_PREEMPTION</code> | 2613 | » ··因此,·我们提供了内核选项·<code·class="literal">FULL_PREEMPTION</code> |
2614 | » ··来启用针对所有内核线程的抢占,·这一选项主要用于调试目的。</p></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67135416"></a>8.3.3. 线程迁移</h3></div></div></div><a·id="idp67136056"·class="indexterm"></a><p>简单地说,·线程从一个·CPU·移动到另一个上的过程称作迁移。 | 2614 | » ··来启用针对所有内核线程的抢占,·这一选项主要用于调试目的。</p></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67151800"></a>8.3.3. 线程迁移</h3></div></div></div><a·id="idp67152440"·class="indexterm"></a><p>简单地说,·线程从一个·CPU·移动到另一个上的过程称作迁移。 |
2615 | » 在非抢占式内核中,·这只会在明确定义的点,·例如调用 | 2615 | » 在非抢占式内核中,·这只会在明确定义的点,·例如调用 |
2616 | » <code·class="function">msleep</code>·或返回至用户态时才会发生。 | 2616 | » <code·class="function">msleep</code>·或返回至用户态时才会发生。 |
2617 | » 但是,·在抢占式内核中,·中断可能会在任何时候强制抢断, | 2617 | » 但是,·在抢占式内核中,·中断可能会在任何时候强制抢断, |
2618 | » 并导致迁移。·对于·CPU·私有的数据而言这可能会带来一些负面影响,·因为除 | 2618 | » 并导致迁移。·对于·CPU·私有的数据而言这可能会带来一些负面影响,·因为除 |
2619 | » <code·class="varname">curthread</code>·和·<code·class="varname">curpcb</code> | 2619 | » <code·class="varname">curthread</code>·和·<code·class="varname">curpcb</code> |
2620 | » 以外的数据都可能在迁移过程中发生变化。·由于存在潜在的线程迁移, | 2620 | » 以外的数据都可能在迁移过程中发生变化。·由于存在潜在的线程迁移, |
2621 | » 使得未受保护的·CPU·私有数据访问变得无用。·这就需要在某些代码段禁止迁移, | 2621 | » 使得未受保护的·CPU·私有数据访问变得无用。·这就需要在某些代码段禁止迁移, |
2622 | » 以获得稳定的·CPU·私有数据。</p><a·id="idp67138104"·class="indexterm"></a><p>目前我们采用临界区来避免迁移,·因为它们能够阻止上下文切换。 | 2622 | » 以获得稳定的·CPU·私有数据。</p><a·id="idp67154488"·class="indexterm"></a><p>目前我们采用临界区来避免迁移,·因为它们能够阻止上下文切换。 |
2623 | » 但是,·这有时可能是一种过于严厉的限制, | 2623 | » 但是,·这有时可能是一种过于严厉的限制, |
2624 | » 因为临界区实际上会阻止当前处理器上的中断线程。·因而, | 2624 | » 因为临界区实际上会阻止当前处理器上的中断线程。·因而, |
2625 | » 提供了另一个·API,·用以指示当前进程在被抢断时, | 2625 | » 提供了另一个·API,·用以指示当前进程在被抢断时, |
2626 | » 不应迁移到另一·CPU。</p><p>这组·API·也叫线程牵制,·它由调度器提供。·这组·API·包括两个函数: | 2626 | » 不应迁移到另一·CPU。</p><p>这组·API·也叫线程牵制,·它由调度器提供。·这组·API·包括两个函数: |
2627 | » <code·class="function">sched_pin</code>·和 | 2627 | » <code·class="function">sched_pin</code>·和 |
2628 | » <code·class="function">sched_unpin</code>。·这两个函数用于管理线程私有的计数 | 2628 | » <code·class="function">sched_unpin</code>。·这两个函数用于管理线程私有的计数 |
2629 | » <code·class="varname">td_pinned</code>。·如果嵌套计数大于零,·则线程将被锁住, | 2629 | » <code·class="varname">td_pinned</code>。·如果嵌套计数大于零,·则线程将被锁住, |
Offset 2633, 15 lines modified | Offset 2633, 15 lines modified |
2633 | » 而只有其它线程在受牵制线程没有执行,·且持有 | 2633 | » 而只有其它线程在受牵制线程没有执行,·且持有 |
2634 | » <code·class="varname">sched_lock</code>·锁时才会读嵌套计数,·因此访问 | 2634 | » <code·class="varname">sched_lock</code>·锁时才会读嵌套计数,·因此访问 |
2635 | » <code·class="varname">td_pinned</code>·不必上锁。 | 2635 | » <code·class="varname">td_pinned</code>·不必上锁。 |
2636 | » <code·class="function">sched_pin</code>·函数会使嵌套计数递增, | 2636 | » <code·class="function">sched_pin</code>·函数会使嵌套计数递增, |
2637 | » 而·<code·class="function">sched_unpin</code>·则使其递减。 | 2637 | » 而·<code·class="function">sched_unpin</code>·则使其递减。 |
2638 | » 注意,·这些函数只操作当前线程,·并将其绑定到其执行它时所处的·CPU·上。 | 2638 | » 注意,·这些函数只操作当前线程,·并将其绑定到其执行它时所处的·CPU·上。 |
2639 | » 要将任意线程绑定到指定的·CPU·上,·则应使用·<code·class="function">sched_bind</code>·和 | 2639 | » 要将任意线程绑定到指定的·CPU·上,·则应使用·<code·class="function">sched_bind</code>·和 |
2640 | » <code·class="function">sched_unbind</code>。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67163832"></a>8.3.4. 调出·(Callout)</h3></div></div></div><p>内核机制·<code·class="function">timeout</code>·允许内核服务注册函数, | 2640 | » <code·class="function">sched_unbind</code>。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67159736"></a>8.3.4. 调出·(Callout)</h3></div></div></div><p>内核机制·<code·class="function">timeout</code>·允许内核服务注册函数, |
2641 | » 以作为·<code·class="function">softclock</code>·软件中断的一部分来执行。 | 2641 | » 以作为·<code·class="function">softclock</code>·软件中断的一部分来执行。 |
2642 | » 事件将基于所希望的时钟嘀嗒的数目进行,·并在大约指定的时间回调用户提供的函数。</p><p>未决·timeout·(超时)·事件的全局表是由一全局·mutex, | 2642 | » 事件将基于所希望的时钟嘀嗒的数目进行,·并在大约指定的时间回调用户提供的函数。</p><p>未决·timeout·(超时)·事件的全局表是由一全局·mutex, |
2643 | » <code·class="varname">callout_lock</code>·保护的;·所有对·timeout·表的访问, | 2643 | » <code·class="varname">callout_lock</code>·保护的;·所有对·timeout·表的访问, |
2644 | » 都必须首先拿到这个·mutex。·当·<code·class="function">softclock</code> | 2644 | » 都必须首先拿到这个·mutex。·当·<code·class="function">softclock</code> |
2645 | » 唤醒时,·它会扫描未决超时表,·并找出应启动的那些。·为避免锁逆序, | 2645 | » 唤醒时,·它会扫描未决超时表,·并找出应启动的那些。·为避免锁逆序, |
2646 | » <code·class="function">softclock</code>·线程会在调用所提供的 | 2646 | » <code·class="function">softclock</code>·线程会在调用所提供的 |
2647 | » <code·class="function">timeout</code>·回调函数时首先释放 | 2647 | » <code·class="function">timeout</code>·回调函数时首先释放 |
Offset 2712, 19 lines modified | Offset 2712, 19 lines modified |
2712 | » <code·class="filename">kern/kern_module.c</code>·的源代码。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67225400"></a>8.4.6. Newbus·设备树</h3></div></div></div><a·id="idp67226040"·class="indexterm"></a><p>newbus·系统使用了一个·sx·锁。·读的一方应持有共享·(读) | 2712 | » <code·class="filename">kern/kern_module.c</code>·的源代码。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67225400"></a>8.4.6. Newbus·设备树</h3></div></div></div><a·id="idp67226040"·class="indexterm"></a><p>newbus·系统使用了一个·sx·锁。·读的一方应持有共享·(读) |
2713 | » 锁·(<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=sx_slock&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">sx_slock</span>(9)</span></a>)·而写的一方则应持有排他·(写)·锁 | 2713 | » 锁·(<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=sx_slock&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">sx_slock</span>(9)</span></a>)·而写的一方则应持有排他·(写)·锁 |
2714 | » (<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=sx_xlock&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">sx_xlock</span>(9)</span></a>)。·内部函数一般不需要进行上锁, | 2714 | » (<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=sx_xlock&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">sx_xlock</span>(9)</span></a>)。·内部函数一般不需要进行上锁, |
2715 | » 而外部可见的则应根据需要上锁。·有些项目不需上锁, | 2715 | » 而外部可见的则应根据需要上锁。·有些项目不需上锁, |
2716 | » 因为这些项目在全程是只读的, | 2716 | » 因为这些项目在全程是只读的, |
2717 | » (例如·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=device_get_softc&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">device_get_softc</span>(9)</span></a>),·因而并不会产生竞态条件。 | 2717 | » (例如·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=device_get_softc&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">device_get_softc</span>(9)</span></a>),·因而并不会产生竞态条件。 |
2718 | » 针对·newbus·数据结构的修改相对而言非常少,·因此单个的锁已经足够使用, | 2718 | » 针对·newbus·数据结构的修改相对而言非常少,·因此单个的锁已经足够使用, |
2719 | » 而不致造成性能折损。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67241656"></a>8.4.7. 管道</h3></div></div></div><p>...</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67255096"></a>8.4.8. 进程和线程</h3></div></div></div><p>-·进程层次结构</p><p>-·proc·锁及其参考</p><p>-·在系统调用过程中线程私有的·proc·项副本, | 2719 | » 而不致造成性能折损。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67229368"></a>8.4.7. 管道</h3></div></div></div><p>...</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67246904"></a>8.4.8. 进程和线程</h3></div></div></div><p>-·进程层次结构</p><p>-·proc·锁及其参考</p><p>-·在系统调用过程中线程私有的·proc·项副本, |
2720 | » 包括·td_ucred</p><p>-·进程间操作</p><p>-·进程组和会话</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67257784"></a>8.4.9. 调度器</h3></div></div></div><a·id="idp67258424"·class="indexterm"></a><p>本文在其它地方已经提供了很多关于·<code·class="varname">sched_lock</code> | 2720 | » 包括·td_ucred</p><p>-·进程间操作</p><p>-·进程组和会话</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67249592"></a>8.4.9. 调度器</h3></div></div></div><a·id="idp67250232"·class="indexterm"></a><p>本文在其它地方已经提供了很多关于·<code·class="varname">sched_lock</code> |
2721 | » 的参考和注释。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67259832"></a>8.4.10. Select·和·Poll</h3></div></div></div><p><code·class="function">select</code>·和 | 2721 | » 的参考和注释。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67251640"></a>8.4.10. Select·和·Poll</h3></div></div></div><p><code·class="function">select</code>·和 |
2722 | » <code·class="function">poll</code>·这两个函数允许线程阻塞并等待文件描述符上的事件·-- | 2722 | » <code·class="function">poll</code>·这两个函数允许线程阻塞并等待文件描述符上的事件·-- |
2723 | » 最常见的情况是文件描述符是否可读或可写。</p><p>...</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67262008"></a>8.4.11. SIGIO</h3></div></div></div><p>SIGIO·服务允许进程请求在特定文件描述符的读/写状态发生变化时, | 2723 | » 最常见的情况是文件描述符是否可读或可写。</p><p>...</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67253816"></a>8.4.11. SIGIO</h3></div></div></div><p>SIGIO·服务允许进程请求在特定文件描述符的读/写状态发生变化时, |
2724 | » 将·SIGIO·信号群发给其进程组。·任意给定内核对象上, | 2724 | » 将·SIGIO·信号群发给其进程组。·任意给定内核对象上, |
2725 | » 只允许一进程或进程组注册·SIGIO,·这个进程或进程组称为属主·(owner)。 | 2725 | » 只允许一进程或进程组注册·SIGIO,·这个进程或进程组称为属主·(owner)。 |
2726 | » 每一支持·SIGIO·注册的对象,·都包含一指针字段,·如果对象未注册则为 | 2726 | » 每一支持·SIGIO·注册的对象,·都包含一指针字段,·如果对象未注册则为 |
2727 | » <code·class="constant">NULL</code>, | 2727 | » <code·class="constant">NULL</code>, |
2728 | » 否则是一指向描述这一注册的·<code·class="varname">struct·sigio</code>·的指针。 | 2728 | » 否则是一指向描述这一注册的·<code·class="varname">struct·sigio</code>·的指针。 |
2729 | » 这一字段由一全局·mutex, | 2729 | » 这一字段由一全局·mutex, |
2730 | » <code·class="varname">sigio_lock</code>·保护。·调用·SIGIO·维护函数时, | 2730 | » <code·class="varname">sigio_lock</code>·保护。·调用·SIGIO·维护函数时, |
Offset 2742, 15 lines modified | Offset 2742, 15 lines modified |
2742 | » sigio</code>·中的多数字段在注册过程中都是不变量。 | 2742 | » sigio</code>·中的多数字段在注册过程中都是不变量。 |
2743 | » 一般而言,·开发人员在实现新的支持·SIGIO·的内核对象时, | 2743 | » 一般而言,·开发人员在实现新的支持·SIGIO·的内核对象时, |
2744 | » 会希望避免在调用·SIGIO·支持函数,·例如·<code·class="function">fsetown</code> | 2744 | » 会希望避免在调用·SIGIO·支持函数,·例如·<code·class="function">fsetown</code> |
2745 | » 或·<code·class="function">funsetown</code>·持有结构体锁, | 2745 | » 或·<code·class="function">funsetown</code>·持有结构体锁, |
2746 | » 以免去需要在结构体锁和全局·SIGIO·锁之间定义锁序。 | 2746 | » 以免去需要在结构体锁和全局·SIGIO·锁之间定义锁序。 |
2747 | » 通常可以通过提高结构体上的引用计数来达到这样的目的, | 2747 | » 通常可以通过提高结构体上的引用计数来达到这样的目的, |
2748 | » 例如,·在进行管道操作时,·使用引用某个管道的文件描述符这样的操作, | 2748 | » 例如,·在进行管道操作时,·使用引用某个管道的文件描述符这样的操作, |
2749 | » 就可以照此办理。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67273656"></a>8.4.12. Sysctl</h3></div></div></div><p><code·class="function">sysctl</code>·MIB·服务会从内核内部, | 2749 | » 就可以照此办理。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67265464"></a>8.4.12. Sysctl</h3></div></div></div><p><code·class="function">sysctl</code>·MIB·服务会从内核内部, |
2750 | » 以及用户态的应用程序以系统调用的方式触发。 | 2750 | » 以及用户态的应用程序以系统调用的方式触发。 |
2751 | » 这会引发至少两个和锁有关的问题:·其一是对维持命名空间的数据结构的保护, | 2751 | » 这会引发至少两个和锁有关的问题:·其一是对维持命名空间的数据结构的保护, |
2752 | » 其二是与那些通过·sysctl·接口访问的内核变量和函数之间的交互。 | 2752 | » 其二是与那些通过·sysctl·接口访问的内核变量和函数之间的交互。 |
2753 | » 由于·sysctl·允许直接导出·(甚至修改)·内核统计数据以及配置参数,·sysctl | 2753 | » 由于·sysctl·允许直接导出·(甚至修改)·内核统计数据以及配置参数,·sysctl |
2754 | » 机制必须知道这些变量相应的上锁语义。·目前,·sysctl·使用一个全局·sx | 2754 | » 机制必须知道这些变量相应的上锁语义。·目前,·sysctl·使用一个全局·sx |
2755 | » 锁来实现对·<code·class="function">sysctl</code>·操作的串行化; | 2755 | » 锁来实现对·<code·class="function">sysctl</code>·操作的串行化; |
2756 | » 然而,·这些是假定用全局锁保护的,·并且没有提供其它保护机制。 | 2756 | » 然而,·这些是假定用全局锁保护的,·并且没有提供其它保护机制。 |
Offset 2758, 15 lines modified | Offset 2758, 15 lines modified |
2758 | » copyin·和·copyout、·写新值,·改为·copyin、·上锁、·读旧值、·写新值、 | 2758 | » copyin·和·copyout、·写新值,·改为·copyin、·上锁、·读旧值、·写新值、 |
2759 | » 解锁、·copyout。·一般的·sysctl·只是·copyout·旧值并设置它们·copyin | 2759 | » 解锁、·copyout。·一般的·sysctl·只是·copyout·旧值并设置它们·copyin |
2760 | » 所得到的新值,·仍然可以采用旧式的模型。·然而, | 2760 | » 所得到的新值,·仍然可以采用旧式的模型。·然而, |
2761 | » 对所有·sysctl·处理程序采用第二种模型并避免锁操作方面, | 2761 | » 对所有·sysctl·处理程序采用第二种模型并避免锁操作方面, |
2762 | » 第二种方式可能更规矩一些。</p><p>-·对于通常的情况,·sysctl·可以内嵌一个·mutex·指针到·SYSCTL_FOO | 2762 | » 第二种方式可能更规矩一些。</p><p>-·对于通常的情况,·sysctl·可以内嵌一个·mutex·指针到·SYSCTL_FOO |
2763 | » 宏和结构体中。·这对多数·sysctl·都是有效的。·对于使用·sx | 2763 | » 宏和结构体中。·这对多数·sysctl·都是有效的。·对于使用·sx |
2764 | » 锁、·自旋·mutex,·或其它除单一休眠·mutex·之外的锁策略, | 2764 | » 锁、·自旋·mutex,·或其它除单一休眠·mutex·之外的锁策略, |
2765 | » 可以用·SYSCTL_PROC·节点来完成正确的上锁。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67276216"></a>8.4.13. 任务队列·(Taskqueue)</h3></div></div></div><p>任务队列·(taskqueue)·的接口包括两个与之关联的用于保护相关数据的锁。 | 2765 | » 可以用·SYSCTL_PROC·节点来完成正确的上锁。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67268024"></a>8.4.13. 任务队列·(Taskqueue)</h3></div></div></div><p>任务队列·(taskqueue)·的接口包括两个与之关联的用于保护相关数据的锁。 |
2766 | » <code·class="varname">taskqueue_queues_mutex</code>·是用于保护 | 2766 | » <code·class="varname">taskqueue_queues_mutex</code>·是用于保护 |
2767 | » <code·class="varname">taskqueue_queues</code>·TAILQ·的锁。 | 2767 | » <code·class="varname">taskqueue_queues</code>·TAILQ·的锁。 |
2768 | » 与这个系统关联的另一个·mutex·锁是位于 | 2768 | » 与这个系统关联的另一个·mutex·锁是位于 |
2769 | » <code·class="varname">struct·taskqueue</code>·结构体上。 | 2769 | » <code·class="varname">struct·taskqueue</code>·结构体上。 |
2770 | » 在此处使用同步原语的目的在于保护·<code·class="varname">struct | 2770 | » 在此处使用同步原语的目的在于保护·<code·class="varname">struct |
2771 | » taskqueue</code>·中数据的完整性。·应注意的是, | 2771 | » taskqueue</code>·中数据的完整性。·应注意的是, |
2772 | » 并没有单独的、·帮助用户对其自身的工作进行锁的细化用的宏, | 2772 | » 并没有单独的、·帮助用户对其自身的工作进行锁的细化用的宏, |
Offset 2859, 48 lines modified | Offset 2859, 48 lines modified |
2859 | » <code·class="function">sleepq_lock</code>·对休眠队列上锁。</p><p>休眠线程也可以通过调用·<code·class="function">sleepq_abort</code>·函数来中断其休眠状态。 | 2859 | » <code·class="function">sleepq_lock</code>·对休眠队列上锁。</p><p>休眠线程也可以通过调用·<code·class="function">sleepq_abort</code>·函数来中断其休眠状态。 |
2860 | » 这个函数只有在持有·<code·class="varname">sched_lock</code>·时才能调用, | 2860 | » 这个函数只有在持有·<code·class="varname">sched_lock</code>·时才能调用, |
2861 | » 而且线程必须处于休眠队列之上。·线程也可以通过使用 | 2861 | » 而且线程必须处于休眠队列之上。·线程也可以通过使用 |
2862 | » <code·class="function">sleepq_remove</code>·函数从指定的休眠队列中删除。 | 2862 | » <code·class="function">sleepq_remove</code>·函数从指定的休眠队列中删除。 |
2863 | » 这个函数包括两个参数,·即休眠通道和线程, | 2863 | » 这个函数包括两个参数,·即休眠通道和线程, |
2864 | » 它只在线程处于指定休眠通道的休眠队列之上时才将其唤醒。 | 2864 | » 它只在线程处于指定休眠通道的休眠队列之上时才将其唤醒。 |
2865 | » 如果线程不在那个休眠队列之上,·或同时处于另一等待通道的休眠队列上, | 2865 | » 如果线程不在那个休眠队列之上,·或同时处于另一等待通道的休眠队列上, |
2866 | » 则这个函数将什么都不做而直接返回。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67341624"></a>8.5.2. 十字转门·(turnstile)</h3></div></div></div><a·id="idp67342264"·class="indexterm"></a><p>-·与休眠队列的比较和不同。</p><p>-·查询/等待/释放·(lookup/wait/release) | 2866 | » 则这个函数将什么都不做而直接返回。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67308856"></a>8.5.2. 十字转门·(turnstile)</h3></div></div></div><a·id="idp67309496"·class="indexterm"></a><p>-·与休眠队列的比较和不同。</p><p>-·查询/等待/释放·(lookup/wait/release) |
2867 | ········-·介绍·TDF_TSNOBLOCK·竞态条件。</p><p>-·优先级传播。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67344056"></a>8.5.3. 关于·mutex·实现的一些细节</h3></div></div></div><p>-·我们是否应要求··mtx_destroy()·持有·mutex, | 2867 | ········-·介绍·TDF_TSNOBLOCK·竞态条件。</p><p>-·优先级传播。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67311288"></a>8.5.3. 关于·mutex·实现的一些细节</h3></div></div></div><p>-·我们是否应要求··mtx_destroy()·持有·mutex, |
2868 | » 因为无法安全地断言它们没有被其它对象持有?</p><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67345080"></a>8.5.3.1. 自旋·mutex</h4></div></div></div><a·id="idp67345720"·class="indexterm"></a><p>-·使用一临界区...</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67347000"></a>8.5.3.2. 休眠·mutex</h4></div></div></div><a·id="idp67347640"·class="indexterm"></a><p>-·描述·mutex·冲突时的竞态条件</p><p>-·为何在持有十字转门链锁时,·可以安全地读冲突·mutex·的·mtx_lock。</p></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67353528"></a>8.5.4. Witness</h3></div></div></div><a·id="idp67354168"·class="indexterm"></a><p>-·它能做什么</p><p>-·它如何工作</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="smp-misc"></a>8.6. 其它话题</h2></div></div><·✂ | 2868 | » 因为无法安全地断言它们没有被其它对象持有?</p><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67312312"></a>8.5.3.1. 自旋·mutex</h4></div></div></div><a·id="idp67312952"·class="indexterm"></a><p>-·使用一临界区...</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67314232"></a>8.5.3.2. 休眠·mutex</h4></div></div></div><a·id="idp67314872"·class="indexterm"></a><p>-·描述·mutex·冲突时的竞态条件</p><p>-·为何在持有十字转门链锁时,·可以安全地读冲突·mutex·的·mtx_lock。</p></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67320760"></a>8.5.4. Witness</h3></div></div></div><a·id="idp67321400"·class="indexterm"></a><p>-·它能做什么</p><p>-·它如何工作</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="smp-misc"></a>8.6. 其它话题</h2></div></div><·✂ |
2869 | » <code·class="function">sema_wait</code>?</p><p>-·是否应提供非休眠式·sx·锁?</p><p>-·增加一些关于正确使用引用计数的介绍。</p></div></div><div·class="glossary"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="smp-glossary"></a>术语表</h2></div></div></div><dl><dt><a·id="smp-glossary-atomic"></a><span·class="glossterm">原子</span></dt><dd·class="glossdef"><p>当遵循适当的访问协议时,·如果一操作的效果对其它所有·CPU | 2869 | » <code·class="function">sema_wait</code>?</p><p>-·是否应提供非休眠式·sx·锁?</p><p>-·增加一些关于正确使用引用计数的介绍。</p></div></div><div·class="glossary"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="smp-glossary"></a>术语表</h2></div></div></div><dl><dt><a·id="smp-glossary-atomic"></a><span·class="glossterm">原子</span></dt><dd·class="glossdef"><p>当遵循适当的访问协议时,·如果一操作的效果对其它所有·CPU |
2870 | » ··均可见,·则称其为原子操作。·狭义的原子操作是机器直接提供的。 | 2870 | » ··均可见,·则称其为原子操作。·狭义的原子操作是机器直接提供的。 |
2871 | » ··就更高的抽象层次而言,·如果结构体的多个成员由一个锁保护, | 2871 | » ··就更高的抽象层次而言,·如果结构体的多个成员由一个锁保护, |
2872 | » ··则如果对它们的操作都是在上锁后、·解锁前进行的, | 2872 | » ··则如果对它们的操作都是在上锁后、·解锁前进行的, |
2873 | » ··也可以称其为原子操作。</p><p>参见操作.</p></dd><dt><a·id="smp-glossary-block"></a><span·class="glossterm">阻塞</span></dt><dd·class="glossdef"><p>线程等待锁、·资源或条件时被阻塞。 | 2873 | » ··也可以称其为原子操作。</p><p>参见操作.</p></dd><dt><a·id="smp-glossary-block"></a><span·class="glossterm">阻塞</span></dt><dd·class="glossdef"><p>线程等待锁、·资源或条件时被阻塞。 |
2874 | » ··这一术语也因此被赋予了太多的意涵。</p><p>参见休眠.</p></dd><dt><a·id="smp-glossary-critical-section"></a><span·class="glossterm">临界区</span></dt><dd·class="glossdef"><p>不允许发生抢占的代码段。·使用 | 2874 | » ··这一术语也因此被赋予了太多的意涵。</p><p>参见休眠.</p></dd><dt><a·id="smp-glossary-critical-section"></a><span·class="glossterm">临界区</span></dt><dd·class="glossdef"><p>不允许发生抢占的代码段。·使用 |
2875 | » ··<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=critical_enter&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">critical_enter</span>(9)</span></a>·API·来表示进入和退出临界区。</p></dd><dt><a·id="smp-glossary-MD"></a><span·class="glossterm">MD</span></dt><dd·class="glossdef"><p>表示与机器/平台有关。</p><p>参见MI.</p></dd><dt><a·id="smp-glossary-memory-operation"></a><span·class="glossterm">内存操作</span></dt><dd·class="glossdef"><p>内存操作包括读或写内存中的指定位置。</p></dd><dt><a·id="smp-glossary-MI"></a><span·class="glossterm">MI</span></dt><dd·class="glossdef"><p>表示与机器/平台无关。</p><p>参见MD.</p></dd><dt><a·id="smp-glossary-operation"></a><span·class="glossterm">操作</span></dt><dd><p>见内存操作.</p></dd><dt><a·id="smp-glossary-primary-interrupt-context"></a><span·class="glossterm">主中断上下文</span></dt><dd·class="glossdef"><p>主中断上下文表示当发生中断时所执行的那段代码。 | 2875 | » ··<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=critical_enter&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">critical_enter</span>(9)</span></a>·API·来表示进入和退出临界区。</p></dd><dt><a·id="smp-glossary-MD"></a><span·class="glossterm">MD</span></dt><dd·class="glossdef"><p>表示与机器/平台有关。</p><p>参见MI.</p></dd><dt><a·id="smp-glossary-memory-operation"></a><span·class="glossterm">内存操作</span></dt><dd·class="glossdef"><p>内存操作包括读或写内存中的指定位置。</p></dd><dt><a·id="smp-glossary-MI"></a><span·class="glossterm">MI</span></dt><dd·class="glossdef"><p>表示与机器/平台无关。</p><p>参见MD.</p></dd><dt><a·id="smp-glossary-operation"></a><span·class="glossterm">操作</span></dt><dd><p>见内存操作.</p></dd><dt><a·id="smp-glossary-primary-interrupt-context"></a><span·class="glossterm">主中断上下文</span></dt><dd·class="glossdef"><p>主中断上下文表示当发生中断时所执行的那段代码。 |
2876 | » ··这些代码可以直接运行某个中断处理程序,·或调度一异步终端线程, | 2876 | » ··这些代码可以直接运行某个中断处理程序,·或调度一异步终端线程, |
2877 | » ··以便为给定的中断源执行中断处理程序。</p></dd><dt><span·class="glossterm">实时内核线程</span></dt><dd·class="glossdef"><p>一种高优先级的内核线程。·目前, | 2877 | » ··以便为给定的中断源执行中断处理程序。</p></dd><dt><span·class="glossterm">实时内核线程</span></dt><dd·class="glossdef"><p>一种高优先级的内核线程。·目前, |
2878 | » ··只有中断线程属于实时优先级的内核线程。</p><p>参见线程.</p></dd><dt><a·id="smp-glossary-sleep"></a><span·class="glossterm">休眠</span></dt><dd·class="glossdef"><p>当进程由条件变量或通过·<code·class="function">msleep</code>·或 | 2878 | » ··只有中断线程属于实时优先级的内核线程。</p><p>参见线程.</p></dd><dt><a·id="smp-glossary-sleep"></a><span·class="glossterm">休眠</span></dt><dd·class="glossdef"><p>当进程由条件变量或通过·<code·class="function">msleep</code>·或 |
2879 | » ··<code·class="function">tsleep</code>·阻塞并进入休眠队列时,·称其进入休眠状态。</p><p>参见阻塞.</p></dd><dt><a·id="smp-glossary-sleepable-lock"></a><span·class="glossterm">可休眠锁</span></dt><dd·class="glossdef"><p>可休眠锁是一种在进程休眠时仍可持有的锁。 | 2879 | » ··<code·class="function">tsleep</code>·阻塞并进入休眠队列时,·称其进入休眠状态。</p><p>参见阻塞.</p></dd><dt><a·id="smp-glossary-sleepable-lock"></a><span·class="glossterm">可休眠锁</span></dt><dd·class="glossdef"><p>可休眠锁是一种在进程休眠时仍可持有的锁。 |
2880 | » ··锁管理器·(lockmgr)·锁和·sx·锁是目前·FreeBSD·中仅有的可休眠锁。 | 2880 | » ··锁管理器·(lockmgr)·锁和·sx·锁是目前·FreeBSD·中仅有的可休眠锁。 |
2881 | » ··最终,·某些·sx·锁,·例如·allproc·(全部进程)·和·proctree·(进程树) | 2881 | » ··最终,·某些·sx·锁,·例如·allproc·(全部进程)·和·proctree·(进程树) |
2882 | » ··锁将成为不可休眠锁。</p><p>参见休眠.</p></dd><dt><a·id="smp-glossary-thread"></a><span·class="glossterm">线程</span></dt><dd·class="glossdef"><p>由·struct·thread·所表达的内核线程。·线程可以持有锁, | 2882 | » ··锁将成为不可休眠锁。</p><p>参见休眠.</p></dd><dt><a·id="smp-glossary-thread"></a><span·class="glossterm">线程</span></dt><dd·class="glossdef"><p>由·struct·thread·所表达的内核线程。·线程可以持有锁, |
2883 | » ··并拥有独立的执行上下文。</p></dd><dt><a·id="smp-glossary-wait-channel"></a><span·class="glossterm">等待通道</span></dt><dd·class="glossdef"><p>线程可以在其上休眠的内核虚拟地址。</p></dd></dl></div></div></div><div·class="part"><div·xmlns=""·class="titlepage"><div><div><h1·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="devicedrivers"></a>部分 II. 设备驱动程序</h1></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="chapter"><a·href="#driverbasics">9.·编写·FreeBSD·设备驱动程序</a></span></dt><dd><dl><dt><span·class="sect1"><a·href="#driverbasics-intro">9.1.·简介</a></span></dt><dt><span·class="sect1"><a·href="#driverbasics-kld">9.2.·动态内核链接工具──KLD</a></span></dt><dt><span·class="sect1"><a·href="#driverbasics-access">9.3.·访问设备驱动程序</a></span></dt><dt><span·class="sect1"><a·href="#driverbasics-char">9.4.·字符设备</a></span></dt><dt><span·class="sect1"><a·href="#driverbasics-block">9.5.·块设备(消亡中)</a></span></dt><dt><span·class="sect1"><a·href="#driverbasics-net">9.6.·网络设备驱动程序</a></span></dt></dl></dd><dt><span·c·✂ | 2883 | » ··并拥有独立的执行上下文。</p></dd><dt><a·id="smp-glossary-wait-channel"></a><span·class="glossterm">等待通道</span></dt><dd·class="glossdef"><p>线程可以在其上休眠的内核虚拟地址。</p></dd></dl></div></div></div><div·class="part"><div·xmlns=""·class="titlepage"><div><div><h1·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="devicedrivers"></a>部分 II. 设备驱动程序</h1></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="chapter"><a·href="#driverbasics">9.·编写·FreeBSD·设备驱动程序</a></span></dt><dd><dl><dt><span·class="sect1"><a·href="#driverbasics-intro">9.1.·简介</a></span></dt><dt><span·class="sect1"><a·href="#driverbasics-kld">9.2.·动态内核链接工具──KLD</a></span></dt><dt><span·class="sect1"><a·href="#driverbasics-access">9.3.·访问设备驱动程序</a></span></dt><dt><span·class="sect1"><a·href="#driverbasics-char">9.4.·字符设备</a></span></dt><dt><span·class="sect1"><a·href="#driverbasics-block">9.5.·块设备(消亡中)</a></span></dt><dt><span·class="sect1"><a·href="#driverbasics-net">9.6.·网络设备驱动程序</a></span></dt></dl></dd><dt><span·c·✂ |
2884 | ······这儿的上下文中多用于指代系统中硬件相关的东西,如磁盘,打印机, | 2884 | ······这儿的上下文中多用于指代系统中硬件相关的东西,如磁盘,打印机, |
2885 | ······图形显式器及其键盘。设备驱动程序是操作系统中用于控制特定设备的 | 2885 | ······图形显式器及其键盘。设备驱动程序是操作系统中用于控制特定设备的 |
2886 | ······软件组件。也有所谓的伪设备,即设备驱动程序用软件模拟设备的行为, | 2886 | ······软件组件。也有所谓的伪设备,即设备驱动程序用软件模拟设备的行为, |
2887 | ······而没有特定的底层硬件。设备驱动程序可以被静态地编译进系统,或者 | 2887 | ······而没有特定的底层硬件。设备驱动程序可以被静态地编译进系统,或者 |
2888 | ······通过动态内核链接工具‘kld’在需要时加载。</p><a·id="idp67424312"·class="indexterm"></a><a·id="idp67424824"·class="indexterm"></a><p>类<span·class="trademark">UNIX</span>®操作系统中的大多数设备都是通过设备节点来访问的,有时也 | 2888 | ······通过动态内核链接工具‘kld’在需要时加载。</p><a·id="idp67379256"·class="indexterm"></a><a·id="idp67379768"·class="indexterm"></a><p>类<span·class="trademark">UNIX</span>®操作系统中的大多数设备都是通过设备节点来访问的,有时也 |
2889 | ······被称为特殊文件。这些文件在文件系统的层次结构中通常位于 | 2889 | ······被称为特殊文件。这些文件在文件系统的层次结构中通常位于 |
2890 | ······<code·class="filename">/dev</code>目录下。在FreeBSD·5.0-RELEASE以前的 | 2890 | ······<code·class="filename">/dev</code>目录下。在FreeBSD·5.0-RELEASE以前的 |
2891 | ······发行版中,·对<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=devfs&sektion=5&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">devfs</span>(5)</span></a>的支持还没有被集成到FreeBSD中,每个设备 | 2891 | ······发行版中,·对<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=devfs&sektion=5&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">devfs</span>(5)</span></a>的支持还没有被集成到FreeBSD中,每个设备 |
2892 | ······节点必须要静态创建,并且独立于相关设备驱动程序的存在。系统中大 | 2892 | ······节点必须要静态创建,并且独立于相关设备驱动程序的存在。系统中大 |
2893 | ······多数设备节点是通过运行<code·class="command">MAKEDEV</code>创建的。</p><p>设备驱动程序可以粗略地分为两类,字符和网络设备驱动程序。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="driverbasics-kld"></a>9.2. 动态内核链接工具──KLD</h2></div></div></div><a·id="idp67429176"·class="indexterm"></a><a·id="idp67429944"·class="indexterm"></a><p>kld接口允许系统管理员从运行的系统中动态地添加和删除功能。 | 2893 | ······多数设备节点是通过运行<code·class="command">MAKEDEV</code>创建的。</p><p>设备驱动程序可以粗略地分为两类,字符和网络设备驱动程序。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="driverbasics-kld"></a>9.2. 动态内核链接工具──KLD</h2></div></div></div><a·id="idp67384120"·class="indexterm"></a><a·id="idp67384888"·class="indexterm"></a><p>kld接口允许系统管理员从运行的系统中动态地添加和删除功能。 |
2894 | ······这允许设备驱动程序的编写者将他们的新改动加载到运行的内核中, | 2894 | ······这允许设备驱动程序的编写者将他们的新改动加载到运行的内核中, |
2895 | ······而不用为了测试新改动而频繁地重启。</p><p>kld接口通过下面的特权命令使用: | 2895 | ······而不用为了测试新改动而频繁地重启。</p><p>kld接口通过下面的特权命令使用: |
| |
2896 | ····<a·id="idp67431096"·class="indexterm"></a> | 2896 | ····<a·id="idp67386040"·class="indexterm"></a> |
2897 | ····<a·id="idp67444152"·class="indexterm"></a> | 2897 | ····<a·id="idp67386808"·class="indexterm"></a> |
2898 | ····<a·id="idp67444920"·class="indexterm"></a> | 2898 | ····<a·id="idp67387576"·class="indexterm"></a> |
2899 | ····</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><code·class="command">kldload</code>·-·加载新内核模块 | 2899 | ····</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><code·class="command">kldload</code>·-·加载新内核模块 |
2900 | ········</li><li·class="listitem"><code·class="command">kldunload</code>·-·卸载内核模块 | 2900 | ········</li><li·class="listitem"><code·class="command">kldunload</code>·-·卸载内核模块 |
2901 | ········</li><li·class="listitem"><code·class="command">kldstat</code>·-·列举当前加载的模块 | 2901 | ········</li><li·class="listitem"><code·class="command">kldstat</code>·-·列举当前加载的模块 |
2902 | ········</li></ul></div><p> | 2902 | ········</li></ul></div><p> |
2903 | ····</p><p>内核模块的程序框架</p><pre·class="programlisting">/* | 2903 | ····</p><p>内核模块的程序框架</p><pre·class="programlisting">/* |
2904 | ·*·KLD程序框架 | 2904 | ·*·KLD程序框架 |
2905 | ·*·受Andrew·Reiter在Daemonnews上的文章所启发 | 2905 | ·*·受Andrew·Reiter在Daemonnews上的文章所启发 |
Offset 2940, 35 lines modified | Offset 2940, 35 lines modified |
| |
2940 | static·moduledata_t·skel_mod·=·{ | 2940 | static·moduledata_t·skel_mod·=·{ |
2941 | ··"skel", | 2941 | ··"skel", |
2942 | ··skel_loader, | 2942 | ··skel_loader, |
2943 | ··NULL | 2943 | ··NULL |
2944 | }; | 2944 | }; |
| |
2945 | DECLARE_MODULE(skeleton,·skel_mod,·SI_SUB_KLD,·SI_ORDER_ANY);</pre><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67449272"></a>9.2.1. Makefile</h3></div></div></div><p>FreeBSD提供了一个makefile包含文件,利用它你可以快速地编译 | 2945 | DECLARE_MODULE(skeleton,·skel_mod,·SI_SUB_KLD,·SI_ORDER_ANY);</pre><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67400120"></a>9.2.1. Makefile</h3></div></div></div><p>FreeBSD提供了一个makefile包含文件,利用它你可以快速地编译 |
2946 | ········你附加到内核的东西。</p><pre·class="programlisting">SRCS=skeleton.c | 2946 | ········你附加到内核的东西。</p><pre·class="programlisting">SRCS=skeleton.c |
2947 | KMOD=skeleton | 2947 | KMOD=skeleton |
| |
2948 | .include·<bsd.kmod.mk></pre><p>简单地用这个makefile运行<code·class="command">make</code>就能够创建文件 | 2948 | .include·<bsd.kmod.mk></pre><p>简单地用这个makefile运行<code·class="command">make</code>就能够创建文件 |
2949 | ········<code·class="filename">skeleton.ko</code>,键入如下命令可以把它加载到内核: | 2949 | ········<code·class="filename">skeleton.ko</code>,键入如下命令可以把它加载到内核: |
2950 | </p><pre·class="screen"><code·class="prompt">#</code>·<strong·class="userinput"><code>kldload·-v·./skeleton.ko</code></strong></pre><p> | 2950 | </p><pre·class="screen"><code·class="prompt">#</code>·<strong·class="userinput"><code>kldload·-v·./skeleton.ko</code></strong></pre><p> |
2951 | ······</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="driverbasics-access"></a>9.3. 访问设备驱动程序</h2></div></div></div><p><span·class="trademark">UNIX</span>®·提供了一套公共的系统调用供用户的应用程序使用。当用户访问 | 2951 | ······</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="driverbasics-access"></a>9.3. 访问设备驱动程序</h2></div></div></div><p><span·class="trademark">UNIX</span>®·提供了一套公共的系统调用供用户的应用程序使用。当用户访问 |
2952 | ······设备节点时,内核的上层将这些调用分发到相应的设备驱动程序。脚本 | 2952 | ······设备节点时,内核的上层将这些调用分发到相应的设备驱动程序。脚本 |
2953 | ······<code·class="command">/dev/MAKEDEV</code>为你的系统生成了大多数的设备节点, | 2953 | ······<code·class="command">/dev/MAKEDEV</code>为你的系统生成了大多数的设备节点, |
2954 | ······但如果你正在开发你自己的驱动程序,可能需要用 | 2954 | ······但如果你正在开发你自己的驱动程序,可能需要用 |
2955 | ······<code·class="command">mknod</code>创建你自己的设备节点。 | 2955 | ······<code·class="command">mknod</code>创建你自己的设备节点。 |
2956 | ····</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67455288"></a>9.3.1. 创建静态设备节点</h3></div></div></div><a·id="idp67455928"·class="indexterm"></a><a·id="idp67456696"·class="indexterm"></a><p><code·class="command">mknod</code>命令需要四个参数来创建设备节点。 | 2956 | ····</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67434808"></a>9.3.1. 创建静态设备节点</h3></div></div></div><a·id="idp67447736"·class="indexterm"></a><a·id="idp67448504"·class="indexterm"></a><p><code·class="command">mknod</code>命令需要四个参数来创建设备节点。 |
2957 | ········你必须指定设备节点的名字,设备的类型,设备的主号码和设备的从号码。 | 2957 | ········你必须指定设备节点的名字,设备的类型,设备的主号码和设备的从号码。 |
2958 | ······</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67457976"></a>9.3.2. 动态设备节点</h3></div></div></div><a·id="idp67458616"·class="indexterm"></a><a·id="idp67459384"·class="indexterm"></a><p>设备文件系统,或者说devfs,在全局文件系统名字空间中提供对 | 2958 | ······</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67449784"></a>9.3.2. 动态设备节点</h3></div></div></div><a·id="idp67450424"·class="indexterm"></a><a·id="idp67451192"·class="indexterm"></a><p>设备文件系统,或者说devfs,在全局文件系统名字空间中提供对 |
2959 | ········内核设备名字空间的访问。这消除了由于有设备驱动程序而没有静态 | 2959 | ········内核设备名字空间的访问。这消除了由于有设备驱动程序而没有静态 |
2960 | ········设备节点,或者有设备节点而没有安装设备驱动程序而带来的潜在问题。 | 2960 | ········设备节点,或者有设备节点而没有安装设备驱动程序而带来的潜在问题。 |
2961 | ········Devfs仍在进展中,但已经能够工作得相当好了。</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="driverbasics-char"></a>9.4. 字符设备</h2></div></div></div><a·id="idp67461304"·class="indexterm"></a><p>字符设备驱动程序直接从用户进程传输数据,或传输数据到用户进程。 | 2961 | ········Devfs仍在进展中,但已经能够工作得相当好了。</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="driverbasics-char"></a>9.4. 字符设备</h2></div></div></div><a·id="idp67457208"·class="indexterm"></a><p>字符设备驱动程序直接从用户进程传输数据,或传输数据到用户进程。 |
2962 | ······这是最普通的一类设备驱动程序,源码树中有大量的简单例子。</p><p>这个简单的伪设备例子会记住你写给它的任何值,并且当你读取它的时候 | 2962 | ······这是最普通的一类设备驱动程序,源码树中有大量的简单例子。</p><p>这个简单的伪设备例子会记住你写给它的任何值,并且当你读取它的时候 |
2963 | ······会将这些值返回给你。下面显示了两个版本,一个适用于FreeBSD 4.X, | 2963 | ······会将这些值返回给你。下面显示了两个版本,一个适用于FreeBSD 4.X, |
2964 | ······一个适用于FreeBSD 5.X。</p><div·class="example"><a·id="idp67462584"></a><div·class="example-title">例 9.1. 适用于FreeBSD 4.X的回显伪设备驱动程序实例</div><div·class="example-contents"><pre·class="programlisting">/* | 2964 | ······一个适用于FreeBSD 5.X。</p><div·class="example"><a·id="idp67458488"></a><div·class="example-title">例 9.1. 适用于FreeBSD 4.X的回显伪设备驱动程序实例</div><div·class="example-contents"><pre·class="programlisting">/* |
2965 | ·*·简单‘echo’伪设备KLD | 2965 | ·*·简单‘echo’伪设备KLD |
2966 | ·* | 2966 | ·* |
2967 | ·*·Murray·Stokely | 2967 | ·*·Murray·Stokely |
2968 | ·*/ | 2968 | ·*/ |
| |
2969 | #define·MIN(a,b)·(((a)·<·(b))·?·(a)·:·(b)) | 2969 | #define·MIN(a,b)·(((a)·<·(b))·?·(a)·:·(b)) |
| |
Offset 3282, 15 lines modified | Offset 3282, 15 lines modified |
3282 | ······知道准确的磁盘内容的能力。这导致对磁盘数据结构(文件系统,数据库等)的 | 3282 | ······知道准确的磁盘内容的能力。这导致对磁盘数据结构(文件系统,数据库等)的 |
3283 | ······可预测的和可靠的崩溃恢复成为不可能。由于写操作被延迟,内核无法向应用 | 3283 | ······可预测的和可靠的崩溃恢复成为不可能。由于写操作被延迟,内核无法向应用 |
3284 | ······程序报告哪个特定的写操作遇到了写错误,这又进一步增加了一致性问题。 | 3284 | ······程序报告哪个特定的写操作遇到了写错误,这又进一步增加了一致性问题。 |
3285 | ······由于这个原因,真正的应用程序从不依赖于块设备,事实上,几乎所有访问 | 3285 | ······由于这个原因,真正的应用程序从不依赖于块设备,事实上,几乎所有访问 |
3286 | ······磁盘的应用程序都尽力指定总是使用字符(或<span·class="quote">“<span·class="quote">raw</span>”</span>)设备。 | 3286 | ······磁盘的应用程序都尽力指定总是使用字符(或<span·class="quote">“<span·class="quote">raw</span>”</span>)设备。 |
3287 | ······由于实现将每个磁盘(分区)同具有不同语义的两个设备混为一谈,从而致使 | 3287 | ······由于实现将每个磁盘(分区)同具有不同语义的两个设备混为一谈,从而致使 |
3288 | ······相关内核代码极大地复杂化,作为推进磁盘I/O基础结构现代化的一部分,FreeBSD | 3288 | ······相关内核代码极大地复杂化,作为推进磁盘I/O基础结构现代化的一部分,FreeBSD |
3289 | ······抛弃了对带缓冲的磁盘设备的支持。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="driverbasics-net"></a>9.6. 网络设备驱动程序</h2></div></div></div><a·id="idp67480888"·class="indexterm"></a><p>访问网络设备的驱动程序不需要使用设备节点。选择哪个驱动程序是 | 3289 | ······抛弃了对带缓冲的磁盘设备的支持。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="driverbasics-net"></a>9.6. 网络设备驱动程序</h2></div></div></div><a·id="idp67476792"·class="indexterm"></a><p>访问网络设备的驱动程序不需要使用设备节点。选择哪个驱动程序是 |
3290 | ······基于内核内部的其他决定而不是调用open(),对网络设备的使用通常由 | 3290 | ······基于内核内部的其他决定而不是调用open(),对网络设备的使用通常由 |
3291 | ······系统调用socket(2)引入。</p><p>更多细节,·请参见·ifnet(9)·联机手册、·回环设备的源代码, | 3291 | ······系统调用socket(2)引入。</p><p>更多细节,·请参见·ifnet(9)·联机手册、·回环设备的源代码, |
3292 | ······以及·Bill·Paul·撰写的网络驱动程序。</p></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="isa-driver"></a>第 10 章 ISA设备驱动程序</h2></div><div><span·class="authorgroup">写作:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Sergey</span>·<span·class="surname">Babkin</span></span>.·</span></div><div><span·class="authorgroup">改编为手册:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Murray</span>·<span·class="surname">Stokely</span></span>,·<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Valentino</span>·<span·class="surname">Vaschetto</span></span>·和·<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Wylie</span>·<span·class="surname">Stilwell</span></span>.·</span></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><d·✂ | 3292 | ······以及·Bill·Paul·撰写的网络驱动程序。</p></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="isa-driver"></a>第 10 章 ISA设备驱动程序</h2></div><div><span·class="authorgroup">写作:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Sergey</span>·<span·class="surname">Babkin</span></span>.·</span></div><div><span·class="authorgroup">改编为手册:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Murray</span>·<span·class="surname">Stokely</span></span>,·<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Valentino</span>·<span·class="surname">Vaschetto</span></span>·和·<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Wylie</span>·<span·class="surname">Stilwell</span></span>.·</span></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><d·✂ |
3293 | ······相当详细,很容易让人联想到真正的代码,不过这依然仅仅是伪代码。 | 3293 | ······相当详细,很容易让人联想到真正的代码,不过这依然仅仅是伪代码。 |
3294 | ······它避免了与所讨论的主题无关的细节。真实的例子可以在实际驱动程序的 | 3294 | ······它避免了与所讨论的主题无关的细节。真实的例子可以在实际驱动程序的 |
3295 | ······源代码中找到。<code·class="literal">ep</code>和<code·class="literal">aha</code> | 3295 | ······源代码中找到。<code·class="literal">ep</code>和<code·class="literal">aha</code> |
3296 | ······更是信息的好来源。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="isa-driver-basics"></a>10.2. 基本信息</h2></div></div></div><p>典型的ISA驱动程序需要以下包含文件:</p><pre·class="programlisting">#include·<sys/module.h> | 3296 | ······更是信息的好来源。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="isa-driver-basics"></a>10.2. 基本信息</h2></div></div></div><p>典型的ISA驱动程序需要以下包含文件:</p><pre·class="programlisting">#include·<sys/module.h> |
Offset 3382, 16 lines modified | Offset 3382, 16 lines modified |
3382 | » ··*device_get_softc(dev)</code>·获取指向与设备关联的设备描述符 | 3382 | » ··*device_get_softc(dev)</code>·获取指向与设备关联的设备描述符 |
3383 | ··········(<code·class="varname">xxx_softc</code>结构)的指针。 | 3383 | ··········(<code·class="varname">xxx_softc</code>结构)的指针。 |
3384 | » ··</p></li><li·class="listitem"><p><code·class="function">u_int32_t | 3384 | » ··</p></li><li·class="listitem"><p><code·class="function">u_int32_t |
3385 | » ··device_get_flags(dev)</code>·获取配置文件中特定于设备的 | 3385 | » ··device_get_flags(dev)</code>·获取配置文件中特定于设备的 |
3386 | ··········标志。</p></li></ul></div><p>可以使用一个很方便的函数<code·class="function">device_printf(dev,·fmt, | 3386 | ··········标志。</p></li></ul></div><p>可以使用一个很方便的函数<code·class="function">device_printf(dev,·fmt, |
3387 | » ...)</code>从设备驱动程序中打印讯息。它自动在讯息前添加 | 3387 | » ...)</code>从设备驱动程序中打印讯息。它自动在讯息前添加 |
3388 | ········单元名和冒号。</p><p>device_t的这些方法在文件<code·class="filename">kern/bus_subr.c</code> | 3388 | ········单元名和冒号。</p><p>device_t的这些方法在文件<code·class="filename">kern/bus_subr.c</code> |
3389 | ········中实现。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="isa-driver-config"></a>10.4. 配置文件与自动配置期间识别和探测的顺序</h2></div></div></div><a·id="idp67574712"·class="indexterm"></a><p>ISA设备在内核配置文件中的描述如下:</p><pre·class="programlisting">device·xxx0·at·isa?·port·0x300·irq·10·drq·5 | 3389 | ········中实现。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="isa-driver-config"></a>10.4. 配置文件与自动配置期间识别和探测的顺序</h2></div></div></div><a·id="idp67578808"·class="indexterm"></a><p>ISA设备在内核配置文件中的描述如下:</p><pre·class="programlisting">device·xxx0·at·isa?·port·0x300·irq·10·drq·5 |
3390 | ·······iomem·0xd0000·flags·0x1·sensitive</pre><a·id="idp67576248"·class="indexterm"></a><p>端口值、IRQ值和其他值被转换成与设备关联的资源值。根据设备 | 3390 | ·······iomem·0xd0000·flags·0x1·sensitive</pre><a·id="idp67580344"·class="indexterm"></a><p>端口值、IRQ值和其他值被转换成与设备关联的资源值。根据设备 |
3391 | » 对自动配置需要和支持程度的不同,这些值是可选的。例如, | 3391 | » 对自动配置需要和支持程度的不同,这些值是可选的。例如, |
3392 | » 某些设备根本不需要读DRQ,而有些则允许设备从设备配置端口读取 | 3392 | » 某些设备根本不需要读DRQ,而有些则允许设备从设备配置端口读取 |
3393 | » IRQ设置。如果机器有多个ISA总线,可以在配置文件中明确指定哪条 | 3393 | » IRQ设置。如果机器有多个ISA总线,可以在配置文件中明确指定哪条 |
3394 | » 总线,如<code·class="literal">isa0</code>或<code·class="literal">isa1</code>, | 3394 | » 总线,如<code·class="literal">isa0</code>或<code·class="literal">isa1</code>, |
3395 | » 否则将在所有ISA总线上搜索设备。</p><p><code·class="literal">敏感(sensitive)</code>是一种资源请求,它指示 | 3395 | » 否则将在所有ISA总线上搜索设备。</p><p><code·class="literal">敏感(sensitive)</code>是一种资源请求,它指示 |
3396 | » 必须在所有非敏感设备之前探测设备。此特性虽被支持,但似乎从未 | 3396 | » 必须在所有非敏感设备之前探测设备。此特性虽被支持,但似乎从未 |
3397 | » 在目前的任何驱动程序中使用过。</p><p>对于老的ISA设备,很多情况下驱动程序仍然能够侦测配置参数。 | 3397 | » 在目前的任何驱动程序中使用过。</p><p>对于老的ISA设备,很多情况下驱动程序仍然能够侦测配置参数。 |
Offset 3879, 15 lines modified | Offset 3879, 15 lines modified |
3879 | ··········2.·如果请求是在函数返回时完成(例如字符设备上传统的读写请求), | 3879 | ··········2.·如果请求是在函数返回时完成(例如字符设备上传统的读写请求), |
3880 | ··········则需要在缓冲区描述符上设置同步标志,并调用 | 3880 | ··········则需要在缓冲区描述符上设置同步标志,并调用 |
3881 | ··········<code·class="function">tsleep()</code>。后面当回调函数被调用时,它将 | 3881 | ··········<code·class="function">tsleep()</code>。后面当回调函数被调用时,它将 |
3882 | ··········执行处理并检查同步标志。如果设置了同步标志,它应该发出一个 | 3882 | ··········执行处理并检查同步标志。如果设置了同步标志,它应该发出一个 |
3883 | ··········唤醒操作。在这种方法中,回调函数或者进行所由必需的处理(就像 | 3883 | ··········唤醒操作。在这种方法中,回调函数或者进行所由必需的处理(就像 |
3884 | ··········前面的情况),或者简单在缓冲区描述符中存储段数组。回调完成 | 3884 | ··········前面的情况),或者简单在缓冲区描述符中存储段数组。回调完成 |
3885 | ··········后,回调函数就能使用这个存储的段数组并进行所有的处理。 | 3885 | ··········后,回调函数就能使用这个存储的段数组并进行所有的处理。 |
3886 | ········</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="isa-driver-dma"></a>10.7. DMA</h2></div></div></div><a·id="idp67833784"·class="indexterm"></a><p> | 3886 | ········</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="isa-driver-dma"></a>10.7. DMA</h2></div></div></div><a·id="idp67817400"·class="indexterm"></a><p> |
3887 | ··········ISA总线中Direct·Memory·Access·(DMA)是通过DMA控制器(实际上是它们 | 3887 | ··········ISA总线中Direct·Memory·Access·(DMA)是通过DMA控制器(实际上是它们 |
3888 | ··········中的两个,但这只是无关细节)实现的。为了使以前的ISA设备简单便宜, | 3888 | ··········中的两个,但这只是无关细节)实现的。为了使以前的ISA设备简单便宜, |
3889 | ··········总线控制和地址产生的逻辑都集中在DMA控制器中。幸运的是,FreeBSD | 3889 | ··········总线控制和地址产生的逻辑都集中在DMA控制器中。幸运的是,FreeBSD |
3890 | ··········提供了一套函数,这些函数大多把DMA控制器的繁琐细节对设备驱动程序 | 3890 | ··········提供了一套函数,这些函数大多把DMA控制器的繁琐细节对设备驱动程序 |
3891 | ··········隐藏了起来。 | 3891 | ··········隐藏了起来。 |
3892 | ········</p><p> | 3892 | ········</p><p> |
3893 | ··········最简单情况是那些比较智能的设备。就象PCI上的总线主设备一样, | 3893 | ··········最简单情况是那些比较智能的设备。就象PCI上的总线主设备一样, |
Offset 4432, 15 lines modified | Offset 4432, 15 lines modified |
4432 | ··········当系统要关闭的时候调用此例程。通过它使硬件进入某种一致的状态。 | 4432 | ··········当系统要关闭的时候调用此例程。通过它使硬件进入某种一致的状态。 |
4433 | ··········对于大多数ISA设备而言不需要特殊动作,因此这个函数并非真正必需, | 4433 | ··········对于大多数ISA设备而言不需要特殊动作,因此这个函数并非真正必需, |
4434 | ··········因为不管怎样重启动时设备会被重新初始化。但有些设备必须按特定 | 4434 | ··········因为不管怎样重启动时设备会被重新初始化。但有些设备必须按特定 |
4435 | ··········步骤关闭,以确保在软重启后能被正确地检测到(对于很多使用私有 | 4435 | ··········步骤关闭,以确保在软重启后能被正确地检测到(对于很多使用私有 |
4436 | ··········识别协议的设备特别有用)。很多情况下,在设备寄存器中禁用DMA和 | 4436 | ··········识别协议的设备特别有用)。很多情况下,在设备寄存器中禁用DMA和 |
4437 | ··········中断,并停止将要进行的传输是个好主意。确切动作取决于硬件,因此 | 4437 | ··········中断,并停止将要进行的传输是个好主意。确切动作取决于硬件,因此 |
4438 | ··········我们无法在此详细讨论。 | 4438 | ··········我们无法在此详细讨论。 |
4439 | ········</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="isa-driver-intr"></a>10.12. xxx_intr</h2></div></div></div><a·id="idp67968056"·class="indexterm"></a><p> | 4439 | ········</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="isa-driver-intr"></a>10.12. xxx_intr</h2></div></div></div><a·id="idp68013112"·class="indexterm"></a><p> |
4440 | ··········当收到来自特定设备的中断时就会调用中断处理函数。ISA总线不支持 | 4440 | ··········当收到来自特定设备的中断时就会调用中断处理函数。ISA总线不支持 |
4441 | ··········中断共享(某些特殊情况例外),因此实际上如果中断处理函数被调用, | 4441 | ··········中断共享(某些特殊情况例外),因此实际上如果中断处理函数被调用, |
4442 | ··········几乎可以确信中断是来自其设备。然而,中断处理函数必须轮询设备 | 4442 | ··········几乎可以确信中断是来自其设备。然而,中断处理函数必须轮询设备 |
4443 | ··········寄存器并确保中断是由它的设备产生的。如果不是,中断处理函数应当 | 4443 | ··········寄存器并确保中断是由它的设备产生的。如果不是,中断处理函数应当 |
4444 | ··········返回。 | 4444 | ··········返回。 |
4445 | ········</p><p> | 4445 | ········</p><p> |
4446 | ··········ISA驱动程序的旧约定是取设备单元号作为参量。现在已经废弃,当 | 4446 | ··········ISA驱动程序的旧约定是取设备单元号作为参量。现在已经废弃,当 |
Offset 4460, 16 lines modified | Offset 4460, 16 lines modified |
4460 | ········</p><pre·class="programlisting"> | 4460 | ········</p><pre·class="programlisting"> |
4461 | ··········while(xxx_interrupt_pending(sc))·{ | 4461 | ··········while(xxx_interrupt_pending(sc))·{ |
4462 | ··············xxx_process_interrupt(sc); | 4462 | ··············xxx_process_interrupt(sc); |
4463 | ··············xxx_acknowledge_interrupt(sc); | 4463 | ··············xxx_acknowledge_interrupt(sc); |
4464 | ··········}········</pre><p> | 4464 | ··········}········</pre><p> |
4465 | ··········中断处理函数必须只向设备应答中断,但不能向中断控制器应答,后者由 | 4465 | ··········中断处理函数必须只向设备应答中断,但不能向中断控制器应答,后者由 |
4466 | ··········系统负责处理。 | 4466 | ··········系统负责处理。 |
4467 | ········</p></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="pci"></a>第 11 章 PCI设备</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#pci-probe">11.1.·探测与连接</a></span></dt><dt><span·class="sect1"><a·href="#pci-bus">11.2.·总线资源</a></span></dt></dl></div><a·id="idp67974712"·class="indexterm"></a><p>本章将讨论FreeBSD为了给PCI总线上的设备编写驱动程序而提供的机制。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="pci-probe"></a>11.1. 探测与连接</h2></div></div></div><p>这儿的信息是关于PCI总线代码如何迭代通过未连接的设备,并查看新 | 4467 | ········</p></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="pci"></a>第 11 章 PCI设备</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#pci-probe">11.1.·探测与连接</a></span></dt><dt><span·class="sect1"><a·href="#pci-bus">11.2.·总线资源</a></span></dt></dl></div><a·id="idp68019768"·class="indexterm"></a><p>本章将讨论FreeBSD为了给PCI总线上的设备编写驱动程序而提供的机制。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="pci-probe"></a>11.1. 探测与连接</h2></div></div></div><p>这儿的信息是关于PCI总线代码如何迭代通过未连接的设备,并查看新 |
4468 | ······加载的kld是否会连接其中一个。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67976760"></a>11.1.1. 示例驱动程序源代码(<code·class="filename">mypci.c</code>)</h3></div></div></div><pre·class="programlisting">/* | 4468 | ······加载的kld是否会连接其中一个。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68025912"></a>11.1.1. 示例驱动程序源代码(<code·class="filename">mypci.c</code>)</h3></div></div></div><pre·class="programlisting">/* |
4469 | ·*·与PCI函数进行交互的简单KLD | 4469 | ·*·与PCI函数进行交互的简单KLD |
4470 | ·* | 4470 | ·* |
4471 | ·*·Murray·Stokely | 4471 | ·*·Murray·Stokely |
4472 | ·*/ | 4472 | ·*/ |
| |
4473 | #include·<sys/param.h>» » /*·kernel.h中使用的定义·*/ | 4473 | #include·<sys/param.h>» » /*·kernel.h中使用的定义·*/ |
4474 | #include·<sys/module.h> | 4474 | #include·<sys/module.h> |
Offset 4665, 31 lines modified | Offset 4665, 31 lines modified |
| |
4665 | » {·0,·0·} | 4665 | » {·0,·0·} |
4666 | }; | 4666 | }; |
| |
4667 | static·devclass_t·mypci_devclass; | 4667 | static·devclass_t·mypci_devclass; |
| |
4668 | DEFINE_CLASS_0(mypci,·mypci_driver,·mypci_methods,·sizeof(struct·mypci_softc)); | 4668 | DEFINE_CLASS_0(mypci,·mypci_driver,·mypci_methods,·sizeof(struct·mypci_softc)); |
4669 | DRIVER_MODULE(mypci,·pci,·mypci_driver,·mypci_devclass,·0,·0);</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67978680"></a>11.1.2. 示例驱动程序的<code·class="filename">Makefile</code></h3></div></div></div><pre·class="programlisting">#·驱动程序mypci的Makefile | 4669 | DRIVER_MODULE(mypci,·pci,·mypci_driver,·mypci_devclass,·0,·0);</pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68027832"></a>11.1.2. 示例驱动程序的<code·class="filename">Makefile</code></h3></div></div></div><pre·class="programlisting">#·驱动程序mypci的Makefile |
| |
4670 | KMOD=» mypci | 4670 | KMOD=» mypci |
4671 | SRCS=» mypci.c | 4671 | SRCS=» mypci.c |
4672 | SRCS+=» device_if.h·bus_if.h·pci_if.h | 4672 | SRCS+=» device_if.h·bus_if.h·pci_if.h |
| |
4673 | .include·<bsd.kmod.mk></pre><p>如果你将上面的源文件和 | 4673 | .include·<bsd.kmod.mk></pre><p>如果你将上面的源文件和 |
4674 | » <code·class="filename">Makefile</code>放入一个目录,你可以运行 | 4674 | » <code·class="filename">Makefile</code>放入一个目录,你可以运行 |
4675 | » <code·class="command">make</code>编译示例驱动程序。 | 4675 | » <code·class="command">make</code>编译示例驱动程序。 |
4676 | » 还有,你可以运行<code·class="command">make·load</code> | 4676 | » 还有,你可以运行<code·class="command">make·load</code> |
4677 | » 将驱动程序装载到当前正在运行的内核中,而<code·class="command">make | 4677 | » 将驱动程序装载到当前正在运行的内核中,而<code·class="command">make |
4678 | » unload</code>可在装载后卸载驱动程序。 | 4678 | » unload</code>可在装载后卸载驱动程序。 |
4679 | » </p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68039480"></a>11.1.3. 更多资源</h3></div></div></div><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><a·class="link"·href="http://www.pcisig.org/"·target="_top">PCI | 4679 | » </p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68031288"></a>11.1.3. 更多资源</h3></div></div></div><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><a·class="link"·href="http://www.pcisig.org/"·target="_top">PCI |
4680 | » ··Special·Interest·Group</a></li><li·class="listitem">PCI·System·Architecture,·Fourth·Edition·by | 4680 | » ··Special·Interest·Group</a></li><li·class="listitem">PCI·System·Architecture,·Fourth·Edition·by |
4681 | » ··Tom·Shanley,·et·al.</li></ul></div></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="pci-bus"></a>11.2. 总线资源</h2></div></div></div><a·id="idp68042808"·class="indexterm"></a><p>FreeBSD为从父总线请求资源提供了一种面向对象的机制。几乎所有设备 | 4681 | » ··Tom·Shanley,·et·al.</li></ul></div></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="pci-bus"></a>11.2. 总线资源</h2></div></div></div><a·id="idp68067384"·class="indexterm"></a><p>FreeBSD为从父总线请求资源提供了一种面向对象的机制。几乎所有设备 |
4682 | ······都是某种类型的总线(PCI,·ISA,·USB,·SCSI等等)的孩子成员,并且这些设备 | 4682 | ······都是某种类型的总线(PCI,·ISA,·USB,·SCSI等等)的孩子成员,并且这些设备 |
4683 | ······需要从他们的父总线获取资源(例如内存段,·中断线,·或者DMA通道)。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68043960"></a>11.2.1. 基地址寄存器</h3></div></div></div><a·id="idp68044600"·class="indexterm"></a><p>为了对PCI设备做些有用的事情,你需要从PCI配置空间获取 | 4683 | ······需要从他们的父总线获取资源(例如内存段,·中断线,·或者DMA通道)。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68068536"></a>11.2.1. 基地址寄存器</h3></div></div></div><a·id="idp68069176"·class="indexterm"></a><p>为了对PCI设备做些有用的事情,你需要从PCI配置空间获取 |
4684 | ········<span·class="emphasis"><em>Base·Address·Registers</em></span>·(BARs)。获取BAR时的 | 4684 | ········<span·class="emphasis"><em>Base·Address·Registers</em></span>·(BARs)。获取BAR时的 |
4685 | ········PCI特定的细节被抽象在函数<code·class="function">bus_alloc_resource()</code>中。 | 4685 | ········PCI特定的细节被抽象在函数<code·class="function">bus_alloc_resource()</code>中。 |
4686 | ······</p><p>例如,一个典型的驱动程序可能在<code·class="function">attach()</code> | 4686 | ······</p><p>例如,一个典型的驱动程序可能在<code·class="function">attach()</code> |
4687 | ········函数中有些类似下面的东西:</p><pre·class="programlisting">····sc->bar0id·=·PCIR_BAR(0); | 4687 | ········函数中有些类似下面的东西:</p><pre·class="programlisting">····sc->bar0id·=·PCIR_BAR(0); |
4688 | ····sc->bar0res·=·bus_alloc_resource(dev,·SYS_RES_MEMORY,·&sc->bar0id, | 4688 | ····sc->bar0res·=·bus_alloc_resource(dev,·SYS_RES_MEMORY,·&sc->bar0id, |
4689 | » » » » ··0,·~0,·1,·RF_ACTIVE); | 4689 | » » » » ··0,·~0,·1,·RF_ACTIVE); |
4690 | ····if·(sc->bar0res·==·NULL)·{ | 4690 | ····if·(sc->bar0res·==·NULL)·{ |
Offset 4731, 15 lines modified | Offset 4731, 15 lines modified |
4731 | » ··这样,·您就可以将·<code·class="varname">softc</code> | 4731 | » ··这样,·您就可以将·<code·class="varname">softc</code> |
4732 | » ··中的·bus·tag·和·bus·句柄这两个成员变量去掉,·并将 | 4732 | » ··中的·bus·tag·和·bus·句柄这两个成员变量去掉,·并将 |
4733 | » ··<code·class="function">board_read()</code>·函数改写为:</p><pre·xmlns="http://www.w3.org/1999/xhtml"·class="programlisting">uint16_t | 4733 | » ··<code·class="function">board_read()</code>·函数改写为:</p><pre·xmlns="http://www.w3.org/1999/xhtml"·class="programlisting">uint16_t |
4734 | board_read(struct·ni_softc·*sc,·uint16_t·address) | 4734 | board_read(struct·ni_softc·*sc,·uint16_t·address) |
4735 | { | 4735 | { |
4736 | » return·(bus_read(sc->bar1res,·address)); | 4736 | » return·(bus_read(sc->bar1res,·address)); |
4737 | } | 4737 | } |
4738 | </pre></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68087736"></a>11.2.2. 中断</h3></div></div></div><a·id="idp68088376"·class="indexterm"></a><p>中断按照和分配内存资源相似的方式从面向对象的总线代码分配。首先, | 4738 | </pre></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68079544"></a>11.2.2. 中断</h3></div></div></div><a·id="idp68080184"·class="indexterm"></a><p>中断按照和分配内存资源相似的方式从面向对象的总线代码分配。首先, |
4739 | ········必须从父总线分配IRQ资源,然后必须设置中断处理函数来处理这个IRQ。 | 4739 | ········必须从父总线分配IRQ资源,然后必须设置中断处理函数来处理这个IRQ。 |
4740 | ······</p><p>再一次,来自设备<code·class="function">attach()</code>函数的例子比文字 | 4740 | ······</p><p>再一次,来自设备<code·class="function">attach()</code>函数的例子比文字 |
4741 | ········更具说明性。</p><pre·class="programlisting">/*·取得IRQ资源·*/ | 4741 | ········更具说明性。</p><pre·class="programlisting">/*·取得IRQ资源·*/ |
| |
4742 | ····sc->irqid·=·0x0; | 4742 | ····sc->irqid·=·0x0; |
4743 | ····sc->irqres·=·bus_alloc_resource(dev,·SYS_RES_IRQ,·&(sc->irqid), | 4743 | ····sc->irqres·=·bus_alloc_resource(dev,·SYS_RES_IRQ,·&(sc->irqid), |
4744 | » » » » ··0,·~0,·1,·RF_SHAREABLE·|·RF_ACTIVE); | 4744 | » » » » ··0,·~0,·1,·RF_SHAREABLE·|·RF_ACTIVE); |
Offset 4757, 51 lines modified | Offset 4757, 51 lines modified |
4757 | » printf("Couldn't·set·up·irq\n"); | 4757 | » printf("Couldn't·set·up·irq\n"); |
4758 | » goto·fail4; | 4758 | » goto·fail4; |
4759 | ····} | 4759 | ····} |
4760 | </pre><p>在设备的分离例程中必须注意一些问题。你必须停顿设备的中断流, | 4760 | </pre><p>在设备的分离例程中必须注意一些问题。你必须停顿设备的中断流, |
4761 | ········并移除中断处理函数。一旦<code·class="function">bus_teardown_intr()</code> | 4761 | ········并移除中断处理函数。一旦<code·class="function">bus_teardown_intr()</code> |
4762 | ········返回,你知道你的中断处理函数不会再被调用,并且所有可能已经执行了 | 4762 | ········返回,你知道你的中断处理函数不会再被调用,并且所有可能已经执行了 |
4763 | ········这个中断处理函数的线程都已经返回。由于此函数可以睡眠,调用此函数时 | 4763 | ········这个中断处理函数的线程都已经返回。由于此函数可以睡眠,调用此函数时 |
4764 | ········你必须不能拥有任何互斥体。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68091576"></a>11.2.3. DMA</h3></div></div></div><a·id="idp68092216"·class="indexterm"></a><p>本节已废弃,只是由于历史原因而给出。处理这些问题的适当方法是 | 4764 | ········你必须不能拥有任何互斥体。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68095672"></a>11.2.3. DMA</h3></div></div></div><a·id="idp68096312"·class="indexterm"></a><p>本节已废弃,只是由于历史原因而给出。处理这些问题的适当方法是 |
4765 | ········使用<code·class="function">bus_space_dma*()</code>函数。当更新这一节以反映 | 4765 | ········使用<code·class="function">bus_space_dma*()</code>函数。当更新这一节以反映 |
4766 | ········那样用法时,这段就可能被去掉。然而,目前API还不断有些变动,因此一旦 | 4766 | ········那样用法时,这段就可能被去掉。然而,目前API还不断有些变动,因此一旦 |
4767 | ········它们固定下来后,更新这一节来反映那些改动就很好了。</p><p>在PC上,想进行总线主控DMA的外围设备必须处理物理地址,由于 | 4767 | ········它们固定下来后,更新这一节来反映那些改动就很好了。</p><p>在PC上,想进行总线主控DMA的外围设备必须处理物理地址,由于 |
4768 | ········FreeBSD使用虚拟内存并且只处理虚地址,这仍是个问题。幸运的是,有个 | 4768 | ········FreeBSD使用虚拟内存并且只处理虚地址,这仍是个问题。幸运的是,有个 |
4769 | ········函数,<code·class="function">vtophys()</code>可以帮助我们。</p><pre·class="programlisting">#include·<vm/vm.h> | 4769 | ········函数,<code·class="function">vtophys()</code>可以帮助我们。</p><pre·class="programlisting">#include·<vm/vm.h> |
4770 | #include·<vm/pmap.h> | 4770 | #include·<vm/pmap.h> |
| |
4771 | #define·vtophys(virtual_address)·(...) | 4771 | #define·vtophys(virtual_address)·(...) |
4772 | </pre><p>然而这个解决办法在alpha上有点不一样,并且我们真正想要的是一个 | 4772 | </pre><p>然而这个解决办法在alpha上有点不一样,并且我们真正想要的是一个 |
4773 | ········称为<code·class="function">vtobus()</code>的函数。</p><pre·class="programlisting">#if·defined(__alpha__) | 4773 | ········称为<code·class="function">vtobus()</code>的函数。</p><pre·class="programlisting">#if·defined(__alpha__) |
4774 | #define·vtobus(va)······alpha_XXX_dmamap((vm_offset_t)va) | 4774 | #define·vtobus(va)······alpha_XXX_dmamap((vm_offset_t)va) |
4775 | #else | 4775 | #else |
4776 | #define·vtobus(va)······vtophys(va) | 4776 | #define·vtobus(va)······vtophys(va) |
4777 | #endif | 4777 | #endif |
4778 | </pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp67440824"></a>11.2.4. 取消分配资源</h3></div></div></div><p>取消<code·class="function">attach()</code>期间分配的所有资源非常重要。 | 4778 | </pre></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68104376"></a>11.2.4. 取消分配资源</h3></div></div></div><p>取消<code·class="function">attach()</code>期间分配的所有资源非常重要。 |
4779 | ········必须小心谨慎,即使在失败的条件下也要保证取消分配那些正确的东西, | 4779 | ········必须小心谨慎,即使在失败的条件下也要保证取消分配那些正确的东西, |
4780 | ········这样当你的驱动程序去掉后系统仍然可以使用。</p></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="scsi"></a>第 12 章 通用访问方法SCSI控制器</h2></div><div><span·class="authorgroup">写作:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Sergey</span>·<span·class="surname">Babkin</span></span>.·</span></div><div><span·class="authorgroup">改编为手册:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Murray</span>·<span·class="surname">Stokely</span></span>.·</span></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#scsi-synopsis">12.1.·提纲</a></span></dt><dt><span·class="sect1"><a·href="#scsi-general">12.2.·通用基础结构</a></span></dt><dt><span·class="sect1"><a·href="#scsi-polling">12.3.·轮询</a></span></dt><dt><span·class="s·✂ | 4780 | ········这样当你的驱动程序去掉后系统仍然可以使用。</p></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="scsi"></a>第 12 章 通用访问方法SCSI控制器</h2></div><div><span·class="authorgroup">写作:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Sergey</span>·<span·class="surname">Babkin</span></span>.·</span></div><div><span·class="authorgroup">改编为手册:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Murray</span>·<span·class="surname">Stokely</span></span>.·</span></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#scsi-synopsis">12.1.·提纲</a></span></dt><dt><span·class="sect1"><a·href="#scsi-general">12.2.·通用基础结构</a></span></dt><dt><span·class="sect1"><a·href="#scsi-polling">12.3.·轮询</a></span></dt><dt><span·class="s·✂ |
4781 | ······本文档中很多信息是从以下驱动程序中:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>ncr·(<code·class="filename">/sys/pci/ncr.c</code>) | 4781 | ······本文档中很多信息是从以下驱动程序中:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>ncr·(<code·class="filename">/sys/pci/ncr.c</code>) |
4782 | ·········由Wolfgang·Stanglmeier·and·Stefan·Esser编写</p></li><li·class="listitem"><p>sym·(<code·class="filename">/sys/dev/sym/sym_hipd.c</code>) | 4782 | ·········由Wolfgang·Stanglmeier·and·Stefan·Esser编写</p></li><li·class="listitem"><p>sym·(<code·class="filename">/sys/dev/sym/sym_hipd.c</code>) |
4783 | ·········由Gerard·Roudier编写</p></li><li·class="listitem"><p>aic7xxx | 4783 | ·········由Gerard·Roudier编写</p></li><li·class="listitem"><p>aic7xxx |
4784 | ·········(<code·class="filename">/sys/dev/aic7xxx/aic7xxx.c</code>) | 4784 | ·········(<code·class="filename">/sys/dev/aic7xxx/aic7xxx.c</code>) |
4785 | » ·由Justin·T.·Gibbs编写</p></li></ul></div><p>和从CAM的代码本身(作者·Justin·T.·Gibbs, | 4785 | » ·由Justin·T.·Gibbs编写</p></li></ul></div><p>和从CAM的代码本身(作者·Justin·T.·Gibbs, |
4786 | ·····见<code·class="filename">/sys/cam/*</code>)中摘录。当一些解决方法看起来 | 4786 | ·····见<code·class="filename">/sys/cam/*</code>)中摘录。当一些解决方法看起来 |
4787 | ·····极具逻辑性,并且基本上是从·Justin·T.·Gibbs·的代码中一字不差地摘录时, | 4787 | ·····极具逻辑性,并且基本上是从·Justin·T.·Gibbs·的代码中一字不差地摘录时, |
4788 | ·····我将其标记为<span·class="quote">“<span·class="quote">recommended</span>”</span>。</p><p>本文档以伪代码例子进行说明。尽管有时例子中包含很多细节,并且 | 4788 | ·····我将其标记为<span·class="quote">“<span·class="quote">recommended</span>”</span>。</p><p>本文档以伪代码例子进行说明。尽管有时例子中包含很多细节,并且 |
4789 | ·····看起来很像真正代码,但它仍然只是伪代码。这样写是为了以一种可理解 | 4789 | ·····看起来很像真正代码,但它仍然只是伪代码。这样写是为了以一种可理解 |
4790 | ·····的方式来展示概念。对于真正的驱动程序,其它方法可能更模块化,并且 | 4790 | ·····的方式来展示概念。对于真正的驱动程序,其它方法可能更模块化,并且 |
4791 | ·····更加高效。文档也对硬件细节进行抽象,对于那些会模糊我们所要展示的 | 4791 | ·····更加高效。文档也对硬件细节进行抽象,对于那些会模糊我们所要展示的 |
4792 | ·····概念的问题,或被认为在开发者手册的其他章节中已有描述的问题也做同样 | 4792 | ·····概念的问题,或被认为在开发者手册的其他章节中已有描述的问题也做同样 |
4793 | ·····处理。这些细节通常以调用具有描述性名字的函数、注释或伪语句的形式展现。 | 4793 | ·····处理。这些细节通常以调用具有描述性名字的函数、注释或伪语句的形式展现。 |
4794 | ·····幸运的是,具有实际价值的完整例子,包括所有细节,可以在真正的驱动 | 4794 | ·····幸运的是,具有实际价值的完整例子,包括所有细节,可以在真正的驱动 |
4795 | ·····程序中找到。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="scsi-general"></a>12.2. 通用基础结构</h2></div></div></div><a·id="idp68110776"·class="indexterm"></a><p>CAM代表通用访问方法(Common·Access·Method)。它以类SCSI方式寻址 | 4795 | ·····程序中找到。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="scsi-general"></a>12.2. 通用基础结构</h2></div></div></div><a·id="idp68118968"·class="indexterm"></a><p>CAM代表通用访问方法(Common·Access·Method)。它以类SCSI方式寻址 |
4796 | ······I/O总线。这就允许将通用设备驱动程序和控制I/O总线的驱动程序分离开来: | 4796 | ······I/O总线。这就允许将通用设备驱动程序和控制I/O总线的驱动程序分离开来: |
4797 | ······例如磁盘驱动程序能同时控制SCSI、IDE、且/或任何其他总线上的磁盘, | 4797 | ······例如磁盘驱动程序能同时控制SCSI、IDE、且/或任何其他总线上的磁盘, |
4798 | ······这样磁盘驱动程序部分不必为每种新的I/O总线而重写(或拷贝修改)。 | 4798 | ······这样磁盘驱动程序部分不必为每种新的I/O总线而重写(或拷贝修改)。 |
4799 | ······这样,两个最重要的活动实体是:</p><a·id="idp68123960"·class="indexterm"></a><a·id="idp68124472"·class="indexterm"></a><a·id="idp68124984"·class="indexterm"></a><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><span·class="emphasis"><em>外围设备模块</em></span>·-·外围设备(磁盘, | 4799 | ······这样,两个最重要的活动实体是:</p><a·id="idp68119864"·class="indexterm"></a><a·id="idp68120376"·class="indexterm"></a><a·id="idp68120888"·class="indexterm"></a><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><span·class="emphasis"><em>外围设备模块</em></span>·-·外围设备(磁盘, |
4800 | ········磁带,·CD-ROM等)的驱动程序</p></li><li·class="listitem"><p><span·class="emphasis"><em>SCSI接口模块</em></span>(SIM) | 4800 | ········磁带,·CD-ROM等)的驱动程序</p></li><li·class="listitem"><p><span·class="emphasis"><em>SCSI接口模块</em></span>(SIM) |
4801 | ········-·连接到I/O总线,如SCSI或IDE,的主机总线适配器驱动程序。 | 4801 | ········-·连接到I/O总线,如SCSI或IDE,的主机总线适配器驱动程序。 |
4802 | ······</p></li></ul></div><p>外围设备驱动程序从OS接收请求,将它们转换为SCSI命令序列并将 | 4802 | ······</p></li></ul></div><p>外围设备驱动程序从OS接收请求,将它们转换为SCSI命令序列并将 |
4803 | ······这些SCSI命令传递到SCSI接口模块。SCSI接口模块负责将这些命令传递给 | 4803 | ······这些SCSI命令传递到SCSI接口模块。SCSI接口模块负责将这些命令传递给 |
4804 | ······实际硬件(或者如果实际硬件不是SCSI,而是例如IDE,则也要将这些SCSI | 4804 | ······实际硬件(或者如果实际硬件不是SCSI,而是例如IDE,则也要将这些SCSI |
4805 | ······命令转换为硬件的native命令)。</p><p>由于这儿我们感兴趣的是编写SCSI适配器驱动程序,从此处开始我们 | 4805 | ······命令转换为硬件的native命令)。</p><p>由于这儿我们感兴趣的是编写SCSI适配器驱动程序,从此处开始我们 |
4806 | ······将从SIM的角度考虑所有的事情。</p><p>典型的SIM驱动程序需要包括如下的CAM相关的头文件:</p><pre·class="programlisting">#include·<cam/cam.h> | 4806 | ······将从SIM的角度考虑所有的事情。</p><p>典型的SIM驱动程序需要包括如下的CAM相关的头文件:</p><pre·class="programlisting">#include·<cam/cam.h> |
Offset 4824, 15 lines modified | Offset 4824, 15 lines modified |
4824 | ····if((·sim·=·cam_sim_alloc(action_func,·poll_func,·driver_name, | 4824 | ····if((·sim·=·cam_sim_alloc(action_func,·poll_func,·driver_name, |
4825 | ············softc,·unit,·max_dev_transactions, | 4825 | ············softc,·unit,·max_dev_transactions, |
4826 | ············max_tagged_dev_transactions,·devq)·)==NULL)·{ | 4826 | ············max_tagged_dev_transactions,·devq)·)==NULL)·{ |
4827 | ········cam_simq_free(devq); | 4827 | ········cam_simq_free(devq); |
4828 | ········error;·/*·一些错误处理代码·*/ | 4828 | ········error;·/*·一些错误处理代码·*/ |
4829 | ····}</pre><p>注意如果我们不能创建SIM描述符,我们也释放 | 4829 | ····}</pre><p>注意如果我们不能创建SIM描述符,我们也释放 |
4830 | ······<code·class="varname">devq</code>,因为我们对其无法做任何其他事情, | 4830 | ······<code·class="varname">devq</code>,因为我们对其无法做任何其他事情, |
4831 | ······而且我们想节约内存。</p><a·id="idp68133816"·class="indexterm"></a><p>如果SCSI卡上有多条SCSI总线,则每条总线需要它自己的 | 4831 | ······而且我们想节约内存。</p><a·id="idp68137912"·class="indexterm"></a><p>如果SCSI卡上有多条SCSI总线,则每条总线需要它自己的 |
4832 | ······<code·class="varname">cam_sim</code>·结构。</p><p>一个有趣的问题是,如果SCSI卡有不只一条SCSI总线我们该怎么做, | 4832 | ······<code·class="varname">cam_sim</code>·结构。</p><p>一个有趣的问题是,如果SCSI卡有不只一条SCSI总线我们该怎么做, |
4833 | ······每个卡需要一个<code·class="varname">devq</code>结构还是每条SCSI总线? | 4833 | ······每个卡需要一个<code·class="varname">devq</code>结构还是每条SCSI总线? |
4834 | ······在CAM代码的注释中给出的答案是:任一方式均可,由驱动程序的作者 | 4834 | ······在CAM代码的注释中给出的答案是:任一方式均可,由驱动程序的作者 |
4835 | ······选择。</p><p>参量为: | 4835 | ······选择。</p><p>参量为: |
4836 | ······</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><code·class="function">action_func</code>·-·指向驱动程序 | 4836 | ······</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><code·class="function">action_func</code>·-·指向驱动程序 |
4837 | » ··<code·class="function">xxx_action</code>·函数的指针。 | 4837 | » ··<code·class="function">xxx_action</code>·函数的指针。 |
4838 | » ··</p><div·class="funcsynopsis"><table·border="0"·class="funcprototype-table"·summary="Function·synopsis"·style="cellspacing:·0;·cellpadding:·0;"><tr><td><code·class="funcdef">static·void | 4838 | » ··</p><div·class="funcsynopsis"><table·border="0"·class="funcprototype-table"·summary="Function·synopsis"·style="cellspacing:·0;·cellpadding:·0;"><tr><td><code·class="funcdef">static·void |
Offset 4858, 15 lines modified | Offset 4858, 15 lines modified |
4858 | ··········一个事务,可以将其设置为2,但似乎不值得增加这种复杂性。 | 4858 | ··········一个事务,可以将其设置为2,但似乎不值得增加这种复杂性。 |
4859 | ········</p></li><li·class="listitem"><p>max_tagged_dev_transactions·-·同样的东西,但是 | 4859 | ········</p></li><li·class="listitem"><p>max_tagged_dev_transactions·-·同样的东西,但是 |
4860 | » ··在标签模式下。标签是SCSI在设备上发起多个事务的方式:每个事务 | 4860 | » ··在标签模式下。标签是SCSI在设备上发起多个事务的方式:每个事务 |
4861 | » ··被赋予一个唯一的标签,并被发送到设备。当设备完成某些事务,它 | 4861 | » ··被赋予一个唯一的标签,并被发送到设备。当设备完成某些事务,它 |
4862 | » ··将结果连同标签一起发送回来,这样SCSI适配器(和驱动程序)就能知道 | 4862 | » ··将结果连同标签一起发送回来,这样SCSI适配器(和驱动程序)就能知道 |
4863 | » ··哪个事务完成了。此参量也被认为是最大标签深度。它取决于SCSI | 4863 | » ··哪个事务完成了。此参量也被认为是最大标签深度。它取决于SCSI |
4864 | » ··适配器的能力。</p></li></ul></div><p> | 4864 | » ··适配器的能力。</p></li></ul></div><p> |
4865 | ····</p><a·id="idp67521720"·class="indexterm"></a><p>最后我们注册与我们的SCSI适配器关联的SCSI总线。</p><pre·class="programlisting">····if(xpt_bus_register(sim,·bus_number)·!=·CAM_SUCCESS)·{ | 4865 | ····</p><a·id="idp68152504"·class="indexterm"></a><p>最后我们注册与我们的SCSI适配器关联的SCSI总线。</p><pre·class="programlisting">····if(xpt_bus_register(sim,·bus_number)·!=·CAM_SUCCESS)·{ |
4866 | ········cam_sim_free(sim,·/*free_devq*/·TRUE); | 4866 | ········cam_sim_free(sim,·/*free_devq*/·TRUE); |
4867 | ········error;·/*·一些错误处理代码·*/ | 4867 | ········error;·/*·一些错误处理代码·*/ |
4868 | ····}</pre><p>如果每条SCSI总线有一个<code·class="varname">devq</code>结构(即, | 4868 | ····}</pre><p>如果每条SCSI总线有一个<code·class="varname">devq</code>结构(即, |
4869 | ······我们将带有多条总线的卡看作多个卡,每个卡带有一条总线),则总线号 | 4869 | ······我们将带有多条总线的卡看作多个卡,每个卡带有一条总线),则总线号 |
4870 | ······总是为0,否则SCSI卡上的每条总线应当有不同的号。每条总线需要 | 4870 | ······总是为0,否则SCSI卡上的每条总线应当有不同的号。每条总线需要 |
4871 | ······它自己单独的cam_sim结构。</p><p>这之后我们的控制器完全挂接到CAM系统。现在 | 4871 | ······它自己单独的cam_sim结构。</p><p>这之后我们的控制器完全挂接到CAM系统。现在 |
4872 | ······<code·class="varname">devq</code>的值可以被丢弃:在所有以后从CAM发出的 | 4872 | ······<code·class="varname">devq</code>的值可以被丢弃:在所有以后从CAM发出的 |
Offset 5036, 15 lines modified | Offset 5036, 15 lines modified |
5036 | ········xpt_done(ccb); | 5036 | ········xpt_done(ccb); |
5037 | ········return; | 5037 | ········return; |
5038 | ····} | 5038 | ····} |
5039 | ····if(ccb_h->target_lun·>·OUR_MAX_SUPPORTED_LUN)·{ | 5039 | ····if(ccb_h->target_lun·>·OUR_MAX_SUPPORTED_LUN)·{ |
5040 | ········ccb_h->status·=·CAM_LUN_INVALID; | 5040 | ········ccb_h->status·=·CAM_LUN_INVALID; |
5041 | ········xpt_done(ccb); | 5041 | ········xpt_done(ccb); |
5042 | ········return; | 5042 | ········return; |
5043 | ····}</pre><a·id="idp68208184"·class="indexterm"></a><p>然后分配我们处理请求所需的数据结构(如卡相关的硬件控制块等)。 | 5043 | ····}</pre><a·id="idp68236856"·class="indexterm"></a><p>然后分配我们处理请求所需的数据结构(如卡相关的硬件控制块等)。 |
5044 | ········如果我们不能分配则冻结SIM队列,记录下我们有一个挂起的操作,返回 | 5044 | ········如果我们不能分配则冻结SIM队列,记录下我们有一个挂起的操作,返回 |
5045 | » CCB,请求CAM将CCB重新入队。以后当资源可用时,必须通过返回其 | 5045 | » CCB,请求CAM将CCB重新入队。以后当资源可用时,必须通过返回其 |
5046 | » 状态中设置·<code·class="literal">CAM_SIMQ_RELEASE</code>·位的ccb来解冻SIM队列。否则,如果所有 | 5046 | » 状态中设置·<code·class="literal">CAM_SIMQ_RELEASE</code>·位的ccb来解冻SIM队列。否则,如果所有 |
5047 | » 正常,则将CCB与硬件控制块(HCB)链接,并将其标志为已入队。</p><pre·class="programlisting">····struct·xxx_hcb·*hcb·=·allocate_hcb(softc,·unit,·bus); | 5047 | » 正常,则将CCB与硬件控制块(HCB)链接,并将其标志为已入队。</p><pre·class="programlisting">····struct·xxx_hcb·*hcb·=·allocate_hcb(softc,·unit,·bus); |
| |
5048 | ····if(hcb·==·NULL)·{ | 5048 | ····if(hcb·==·NULL)·{ |
5049 | ········softc->flags·|=·RESOURCE_SHORTAGE; | 5049 | ········softc->flags·|=·RESOURCE_SHORTAGE; |
Offset 5440, 22 lines modified | Offset 5440, 22 lines modified |
5440 | ······(在<code·class="function">xxx_attach()</code>中)当前协商值必须被初始化为 | 5440 | ······(在<code·class="function">xxx_attach()</code>中)当前协商值必须被初始化为 |
5441 | ······最窄同步模式,目的和当前值必须被初始化为控制器所支持的最大值。 | 5441 | ······最窄同步模式,目的和当前值必须被初始化为控制器所支持的最大值。 |
5442 | ······(译注:原文可能有误,此处未改) | 5442 | ······(译注:原文可能有误,此处未改) |
5443 | ······</p></li><li·class="listitem"><p><span·class="emphasis"><em>XPT_GET_TRAN_SETTINGS</em></span>·- | 5443 | ······</p></li><li·class="listitem"><p><span·class="emphasis"><em>XPT_GET_TRAN_SETTINGS</em></span>·- |
5444 | ····获得SCSI传输设置的值</p><p>此操作为XPT_SET_TRAN_SETTINGS的逆操作。用通过旗标 | 5444 | ····获得SCSI传输设置的值</p><p>此操作为XPT_SET_TRAN_SETTINGS的逆操作。用通过旗标 |
5445 | ······CCB_TRANS_CURRENT_SETTINGS或CCB_TRANS_USER_SETTINGS(如果同时设置则 | 5445 | ······CCB_TRANS_CURRENT_SETTINGS或CCB_TRANS_USER_SETTINGS(如果同时设置则 |
5446 | ······现有驱动程序返回当前设置)所请求而得的数据填充CCB实例 | 5446 | ······现有驱动程序返回当前设置)所请求而得的数据填充CCB实例 |
5447 | ······<span·class="quote">“<span·class="quote">struct·ccb_trans_setting·cts</span>”</span>.·</p></li><li·class="listitem"><a·id="idp68411320"·class="indexterm"></a><p><span·class="emphasis"><em>XPT_CALC_GEOMETRY</em></span>·- | 5447 | ······<span·class="quote">“<span·class="quote">struct·ccb_trans_setting·cts</span>”</span>.·</p></li><li·class="listitem"><a·id="idp68378552"·class="indexterm"></a><p><span·class="emphasis"><em>XPT_CALC_GEOMETRY</em></span>·- |
5448 | ······计算磁盘的逻辑(BIOS)结构(geometry)</p><p>参量在联合ccb的实例<span·class="quote">“<span·class="quote">struct·ccb_calc_geometry·ccg</span>”</span> | 5448 | ······计算磁盘的逻辑(BIOS)结构(geometry)</p><p>参量在联合ccb的实例<span·class="quote">“<span·class="quote">struct·ccb_calc_geometry·ccg</span>”</span> |
5449 | ······中传输:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·circle;·"><li·class="listitem"><p><span·class="emphasis"><em>block_size</em></span>·- | 5449 | ······中传输:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·circle;·"><li·class="listitem"><p><span·class="emphasis"><em>block_size</em></span>·- |
5450 | ······输入,以字节计的块大小(也称为扇区)</p></li><li·class="listitem"><p><span·class="emphasis"><em>volume_size</em></span>·- | 5450 | ······输入,以字节计的块大小(也称为扇区)</p></li><li·class="listitem"><p><span·class="emphasis"><em>volume_size</em></span>·- |
5451 | ······输入,以字节计的卷大小</p></li><li·class="listitem"><p><span·class="emphasis"><em>cylinders</em></span>·- | 5451 | ······输入,以字节计的卷大小</p></li><li·class="listitem"><p><span·class="emphasis"><em>cylinders</em></span>·- |
5452 | ······输出,逻辑柱面</p></li><li·class="listitem"><p><span·class="emphasis"><em>heads</em></span>·- | 5452 | ······输出,逻辑柱面</p></li><li·class="listitem"><p><span·class="emphasis"><em>heads</em></span>·- |
5453 | ······输出,逻辑磁头</p></li><li·class="listitem"><p><span·class="emphasis"><em>secs_per_track</em></span>·- | 5453 | ······输出,逻辑磁头</p></li><li·class="listitem"><p><span·class="emphasis"><em>secs_per_track</em></span>·- |
5454 | ······输出,每磁道的逻辑扇区</p></li></ul></div><a·id="idp68417848"·class="indexterm"></a><p>如果返回的结构与SCSI控制器BIOS所想象的差别很大,并且SCSI | 5454 | ······输出,每磁道的逻辑扇区</p></li></ul></div><a·id="idp68397368"·class="indexterm"></a><p>如果返回的结构与SCSI控制器BIOS所想象的差别很大,并且SCSI |
5455 | ······控制器上的磁盘被作为可引导的,则系统可能无法启动。从aic7xxx | 5455 | ······控制器上的磁盘被作为可引导的,则系统可能无法启动。从aic7xxx |
5456 | ······驱动程序中摘取的典型计算示例:</p><pre·class="programlisting">····struct····ccb_calc_geometry·*ccg; | 5456 | ······驱动程序中摘取的典型计算示例:</p><pre·class="programlisting">····struct····ccb_calc_geometry·*ccg; |
5457 | ····u_int32_t·size_mb; | 5457 | ····u_int32_t·size_mb; |
5458 | ····u_int32_t·secs_per_cylinder; | 5458 | ····u_int32_t·secs_per_cylinder; |
5459 | ····int···extended; | 5459 | ····int···extended; |
| |
5460 | ····ccg·=·&ccb->ccg; | 5460 | ····ccg·=·&ccb->ccg; |
Offset 5553, 15 lines modified | Offset 5553, 15 lines modified |
5553 | ············neg.valid·=·(CCB_TRANS_BUS_WIDTH_VALID | 5553 | ············neg.valid·=·(CCB_TRANS_BUS_WIDTH_VALID |
5554 | ················|·CCB_TRANS_SYNC_RATE_VALID·|·CCB_TRANS_SYNC_OFFSET_VALID); | 5554 | ················|·CCB_TRANS_SYNC_RATE_VALID·|·CCB_TRANS_SYNC_OFFSET_VALID); |
5555 | ············xpt_async(AC_TRANSFER_NEG,·path,·&neg); | 5555 | ············xpt_async(AC_TRANSFER_NEG,·path,·&neg); |
5556 | ········} | 5556 | ········} |
5557 | ········break; | 5557 | ········break; |
5558 | ····default: | 5558 | ····default: |
5559 | ········break; | 5559 | ········break; |
5560 | ····}</pre></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="scsi-interrupts"></a>12.5. 中断</h2></div></div></div><a·id="idp68471224"·class="indexterm"></a><p>中断例程的确切类型依赖于SCSI控制器所连接到的外围总线的类型(PCI, | 5560 | ····}</pre></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="scsi-interrupts"></a>12.5. 中断</h2></div></div></div><a·id="idp68434360"·class="indexterm"></a><p>中断例程的确切类型依赖于SCSI控制器所连接到的外围总线的类型(PCI, |
5561 | ······ISA等等)。</p><p>SIM驱动程序的中断例程运行在中断级别splcam上。因此应当在驱动 | 5561 | ······ISA等等)。</p><p>SIM驱动程序的中断例程运行在中断级别splcam上。因此应当在驱动 |
5562 | ······程序中使用<code·class="function">splcam()</code>来同步中断例程与驱动程序 | 5562 | ······程序中使用<code·class="function">splcam()</code>来同步中断例程与驱动程序 |
5563 | ······剩余部分的活动(对于能察觉多处理器的驱动程序,事情更要有趣,但 | 5563 | ······剩余部分的活动(对于能察觉多处理器的驱动程序,事情更要有趣,但 |
5564 | ······此处我们忽略这种情况)。本文档中的伪代码简单地忽略了同步问题。 | 5564 | ······此处我们忽略这种情况)。本文档中的伪代码简单地忽略了同步问题。 |
5565 | ······实际代码一定不能忽略它们。一个较笨的办法就是在进入其他例程的 | 5565 | ······实际代码一定不能忽略它们。一个较笨的办法就是在进入其他例程的 |
5566 | ······入口点处设<code·class="function">splcam()</code>,并在返回时将它复位,从而 | 5566 | ······入口点处设<code·class="function">splcam()</code>,并在返回时将它复位,从而 |
5567 | ······用一个大的临界区保护它们。为了确保中断级别总是会被恢复,可以定义 | 5567 | ······用一个大的临界区保护它们。为了确保中断级别总是会被恢复,可以定义 |
Offset 5836, 15 lines modified | Offset 5836, 15 lines modified |
5836 | ············if(targ·==·h->targ | 5836 | ············if(targ·==·h->targ |
5837 | ············&&·(lun_to_freeze·==·CAM_LUN_WILDCARD·||·lun_to_freeze·==·h->lun)·) | 5837 | ············&&·(lun_to_freeze·==·CAM_LUN_WILDCARD·||·lun_to_freeze·==·h->lun)·) |
5838 | ················free_hcb_and_ccb_done(h,·h->ccb,·CAM_REQUEUE_REQ); | 5838 | ················free_hcb_and_ccb_done(h,·h->ccb,·CAM_REQUEUE_REQ); |
5839 | ········} | 5839 | ········} |
5840 | ····} | 5840 | ····} |
5841 | ····free_hcb_and_ccb_done(hcb,·hcb->ccb,·ccb_status); | 5841 | ····free_hcb_and_ccb_done(hcb,·hcb->ccb,·ccb_status); |
5842 | ····schedule_next_hcb(softc); | 5842 | ····schedule_next_hcb(softc); |
5843 | ····return;</pre><p>这包括通用中断处理,尽管特定处理器可能需要某些附加处理。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="scsi-errors"></a>12.6. 错误总览</h2></div></div></div><a·id="idp68497592"·class="indexterm"></a><p>当执行I/O请求时很多事情可能出错。可以在CCB状态中非常详尽地 | 5843 | ····return;</pre><p>这包括通用中断处理,尽管特定处理器可能需要某些附加处理。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="scsi-errors"></a>12.6. 错误总览</h2></div></div></div><a·id="idp68448440"·class="indexterm"></a><p>当执行I/O请求时很多事情可能出错。可以在CCB状态中非常详尽地 |
5844 | ······报告错误原因。使用的例子散布于本文档中。为了完整起见此处给出 | 5844 | ······报告错误原因。使用的例子散布于本文档中。为了完整起见此处给出 |
5845 | ······对典型错误条件的建议响应的一个总览:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><span·class="emphasis"><em>CAM_RESRC_UNAVAIL</em></span>·-·某些资源 | 5845 | ······对典型错误条件的建议响应的一个总览:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><span·class="emphasis"><em>CAM_RESRC_UNAVAIL</em></span>·-·某些资源 |
5846 | ········暂时不可用,并且当其变为可用时SIM驱动程序不能产生事件。这种资源 | 5846 | ········暂时不可用,并且当其变为可用时SIM驱动程序不能产生事件。这种资源 |
5847 | » 的一个例子就是某些控制器内部硬件资源,当其可用时控制器不会为其 | 5847 | » 的一个例子就是某些控制器内部硬件资源,当其可用时控制器不会为其 |
5848 | » 产生中断。</p></li><li·class="listitem"><p><span·class="emphasis"><em>CAM_UNCOR_PARITY</em></span>·- | 5848 | » 产生中断。</p></li><li·class="listitem"><p><span·class="emphasis"><em>CAM_UNCOR_PARITY</em></span>·- |
5849 | ········发生不可恢复的奇偶校验错误</p></li><li·class="listitem"><p><span·class="emphasis"><em>CAM_DATA_RUN_ERR</em></span>·- | 5849 | ········发生不可恢复的奇偶校验错误</p></li><li·class="listitem"><p><span·class="emphasis"><em>CAM_DATA_RUN_ERR</em></span>·- |
5850 | ········数据外溢或未预期的数据状态(phase)(跑在另一个方向上而不是 | 5850 | ········数据外溢或未预期的数据状态(phase)(跑在另一个方向上而不是 |
Offset 5895, 15 lines modified | Offset 5895, 15 lines modified |
5895 | ········xxx_abort_ccb(hcb->ccb,·CAM_CMD_TIMEOUT); | 5895 | ········xxx_abort_ccb(hcb->ccb,·CAM_CMD_TIMEOUT); |
5896 | ····} | 5896 | ····} |
5897 | }</pre><p>当我们中止一个请求时,同一目标/LUN的所有其他断开连接的请求 | 5897 | }</pre><p>当我们中止一个请求时,同一目标/LUN的所有其他断开连接的请求 |
5898 | ······也会被中止。因此出现了一个问题,我们应当返回它们的状态 | 5898 | ······也会被中止。因此出现了一个问题,我们应当返回它们的状态 |
5899 | ······CAM_REQ_ABORTED还是CAM_CMD_TIMEOUT?当前的驱动程序使用 | 5899 | ······CAM_REQ_ABORTED还是CAM_CMD_TIMEOUT?当前的驱动程序使用 |
5900 | ······CAM_CMD_TIMEOUT。这看起来符合逻辑,因为如果一个请求超时,则可能 | 5900 | ······CAM_CMD_TIMEOUT。这看起来符合逻辑,因为如果一个请求超时,则可能 |
5901 | ······设备出现了某些的确很糟的事情,因此如果它们没有被扰乱则它们自己 | 5901 | ······设备出现了某些的确很糟的事情,因此如果它们没有被扰乱则它们自己 |
5902 | ······应当超时。</p></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="usb"></a>第 13 章 USB设备</h2></div><div><span·class="authorgroup">写作:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Nick</span>·<span·class="surname">Hibma</span></span>.·</span></div><div><span·class="authorgroup">改编为手册:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Murray</span>·<span·class="surname">Stokely</span></span>.·</span></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#usb-intro">13.1.·简介</a></span></dt><dt><span·class="sect1"><a·href="#usb-hc">13.2.·主控器</a></span></dt><dt><span·class="sect1"><a·href="#usb-dev">13.3.·USB设备信息</a></span></dt><dt><span·class="sect1"><a·href="#usb-devprobe">13.4.·设备的探测和连接</a><·✂ | 5902 | ······应当超时。</p></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="usb"></a>第 13 章 USB设备</h2></div><div><span·class="authorgroup">写作:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Nick</span>·<span·class="surname">Hibma</span></span>.·</span></div><div><span·class="authorgroup">改编为手册:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Murray</span>·<span·class="surname">Stokely</span></span>.·</span></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#usb-intro">13.1.·简介</a></span></dt><dt><span·class="sect1"><a·href="#usb-hc">13.2.·主控器</a></span></dt><dt><span·class="sect1"><a·href="#usb-dev">13.3.·USB设备信息</a></span></dt><dt><span·class="sect1"><a·href="#usb-devprobe">13.4.·设备的探测和连接</a><·✂ |
5903 | ······结构突出了双向通信的特色,并且其开发充分考虑到了设备正逐渐智能化 | 5903 | ······结构突出了双向通信的特色,并且其开发充分考虑到了设备正逐渐智能化 |
5904 | ······和需要与host进行更多交互的现实。对USB的支持包含在当前所有芯片中, | 5904 | ······和需要与host进行更多交互的现实。对USB的支持包含在当前所有芯片中, |
5905 | ······因此在新近制造的PC中都可用。苹果(Apple)引入仅带USB的iMac对硬件 | 5905 | ······因此在新近制造的PC中都可用。苹果(Apple)引入仅带USB的iMac对硬件 |
5906 | ······制造商生产他们USB版本的设备是一个很大的激励。未来的PC规范指定 | 5906 | ······制造商生产他们USB版本的设备是一个很大的激励。未来的PC规范指定 |
5907 | ······PC上的所有老连接器应当由一个或多个USB连接器取代,提供通用的 | 5907 | ······PC上的所有老连接器应当由一个或多个USB连接器取代,提供通用的 |
5908 | ······即插即用能力。对USB硬件的支持在NetBSD的相当早期就有了,它是由 | 5908 | ······即插即用能力。对USB硬件的支持在NetBSD的相当早期就有了,它是由 |
5909 | ······Lennart·Augustsson为NetBSD项目开发的。代码已经被移植到FreeBSD上, | 5909 | ······Lennart·Augustsson为NetBSD项目开发的。代码已经被移植到FreeBSD上, |
Offset 5917, 23 lines modified | Offset 5917, 23 lines modified |
5917 | ········可以连接最多126个设备,这就需要恰当地调度总线上的传输以充分 | 5917 | ········可以连接最多126个设备,这就需要恰当地调度总线上的传输以充分 |
5918 | » 利用12Mbps的可用带宽。(USB·2.0超过400Mbps)</p></li><li·class="listitem"><p>设备智能化并包含很容易访问到的关于自身的信息。 | 5918 | » 利用12Mbps的可用带宽。(USB·2.0超过400Mbps)</p></li><li·class="listitem"><p>设备智能化并包含很容易访问到的关于自身的信息。 |
5919 | ········</p></li></ul></div><p>为USB子系统以及连接到它的设备开发驱动程序受已开发或将要开发的 | 5919 | ········</p></li></ul></div><p>为USB子系统以及连接到它的设备开发驱动程序受已开发或将要开发的 |
5920 | ······规范的支持。这些规范可以从USB主页公开获得。苹果(Apple)通过使得 | 5920 | ······规范的支持。这些规范可以从USB主页公开获得。苹果(Apple)通过使得 |
5921 | ······通用类驱动程序可从其操作系统MacOS中获得,而且不鼓励为每种新设备 | 5921 | ······通用类驱动程序可从其操作系统MacOS中获得,而且不鼓励为每种新设备 |
5922 | ······使用单独的驱动程序来强烈推行基于标准的驱动程序。本章试图整理基本 | 5922 | ······使用单独的驱动程序来强烈推行基于标准的驱动程序。本章试图整理基本 |
5923 | ······信息以便对FreeBSD/NetBSD中USB栈的当前实现有个基本的了解。然而, | 5923 | ······信息以便对FreeBSD/NetBSD中USB栈的当前实现有个基本的了解。然而, |
5924 | ······建议将下面参考中提及的相关规范与本章同时阅读。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68576184"></a>13.1.1. USB栈的结构</h3></div></div></div><p>FreeBSD中的USB支持可被分为三层。最底层包含主控器,向硬件 | 5924 | ······建议将下面参考中提及的相关规范与本章同时阅读。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68527032"></a>13.1.1. USB栈的结构</h3></div></div></div><p>FreeBSD中的USB支持可被分为三层。最底层包含主控器,向硬件 |
5925 | ········及其调度设施提供一个通用接口。它支持硬件初始化,对传输进行调度, | 5925 | ········及其调度设施提供一个通用接口。它支持硬件初始化,对传输进行调度, |
5926 | » 处理已完成/失败的传输。每个主控器驱动程序实现一个虚拟hub, | 5926 | » 处理已完成/失败的传输。每个主控器驱动程序实现一个虚拟hub, |
5927 | » 以硬件无关方式提供对控制机器背面根端口的寄存器的访问。</p><p>中间层处理设备连接和断开,设备的基本初始化,驱动程序的选择, | 5927 | » 以硬件无关方式提供对控制机器背面根端口的寄存器的访问。</p><p>中间层处理设备连接和断开,设备的基本初始化,驱动程序的选择, |
5928 | ········通信通道(管道)和资源管理。这个服务层也控制默认管道和其上传输的 | 5928 | ········通信通道(管道)和资源管理。这个服务层也控制默认管道和其上传输的 |
5929 | » 设备请求。</p><p>顶层包含支持特定(类)设备的各个驱动程序。这些驱动程序实现 | 5929 | » 设备请求。</p><p>顶层包含支持特定(类)设备的各个驱动程序。这些驱动程序实现 |
5930 | ········除默认管道外的其他管道上使用的协议。他们也实现额外功能,使得设备 | 5930 | ········除默认管道外的其他管道上使用的协议。他们也实现额外功能,使得设备 |
5931 | » 对内核或用户空间是可见的。他们使用服务层暴露出的USB驱动程序接口 | 5931 | » 对内核或用户空间是可见的。他们使用服务层暴露出的USB驱动程序接口 |
5932 | » (USBDI)。</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="usb-hc"></a>13.2. 主控器</h2></div></div></div><a·id="idp68579000"·class="indexterm"></a><p>主控器(HC)控制总线上包的传输。使用1毫秒的帧。在每帧开始 | 5932 | » (USBDI)。</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="usb-hc"></a>13.2. 主控器</h2></div></div></div><a·id="idp68533944"·class="indexterm"></a><p>主控器(HC)控制总线上包的传输。使用1毫秒的帧。在每帧开始 |
5933 | ······时,主控器产生一个帧开始(SOF,·Start·of·Frame)包。</p><p>SOF包用于同步帧的开始和跟踪帧的数目。包在帧中被传输,或由host | 5933 | ······时,主控器产生一个帧开始(SOF,·Start·of·Frame)包。</p><p>SOF包用于同步帧的开始和跟踪帧的数目。包在帧中被传输,或由host |
5934 | ······到设备(out),或由设备到host(in)。传输总是由host发起(轮询传输)。 | 5934 | ······到设备(out),或由设备到host(in)。传输总是由host发起(轮询传输)。 |
5935 | ······因此每条USB总线只能有一个host。每个包的传输都有一个状态阶段, | 5935 | ······因此每条USB总线只能有一个host。每个包的传输都有一个状态阶段, |
5936 | ······数据接收者可以在其中返回ACK(应答接收),NAK(重试),STALL(错误 | 5936 | ······数据接收者可以在其中返回ACK(应答接收),NAK(重试),STALL(错误 |
5937 | ······条件)或什么也没有(混乱数据阶段,设备不可用或已断开)。USB规范 | 5937 | ······条件)或什么也没有(混乱数据阶段,设备不可用或已断开)。USB规范 |
5938 | ······<a·class="link"·href="http://www.usb.org/developers/docs.html"·target="_top">USB | 5938 | ······<a·class="link"·href="http://www.usb.org/developers/docs.html"·target="_top">USB |
5939 | ······specification</a>的第8.5节更详细地解释了包的细节。USB总线 | 5939 | ······specification</a>的第8.5节更详细地解释了包的细节。USB总线 |
Offset 5951, 15 lines modified | Offset 5951, 15 lines modified |
5951 | ······标准和hub类特定的一组描述符。它也应当提供一个中断管道用来报告其 | 5951 | ······标准和hub类特定的一组描述符。它也应当提供一个中断管道用来报告其 |
5952 | ······端口发生的变化。当前可用的主控器规范有两个: | 5952 | ······端口发生的变化。当前可用的主控器规范有两个: |
5953 | ······<a·class="link"·href="http://developer.intel.com/design/USB/UHCI11D.htm"·target="_top"> | 5953 | ······<a·class="link"·href="http://developer.intel.com/design/USB/UHCI11D.htm"·target="_top"> |
5954 | ······通用主控器接口</a>(UHCI;英特尔)和<a·class="link"·href="http://www.compaq.com/productinfo/development/openhci.html"·target="_top"> | 5954 | ······通用主控器接口</a>(UHCI;英特尔)和<a·class="link"·href="http://www.compaq.com/productinfo/development/openhci.html"·target="_top"> |
5955 | ······开放主控器接口</a>(OHCI;康柏,微软,国家半导体)。 | 5955 | ······开放主控器接口</a>(OHCI;康柏,微软,国家半导体)。 |
5956 | ······UHCI规范的设计通过要求主控器驱动程序为每帧的传输提供完整的调度, | 5956 | ······UHCI规范的设计通过要求主控器驱动程序为每帧的传输提供完整的调度, |
5957 | ······从而减少了硬件复杂性。OHCI类型的控制器自身提供一个更抽象的接口来 | 5957 | ······从而减少了硬件复杂性。OHCI类型的控制器自身提供一个更抽象的接口来 |
5958 | ······完成很多工作,从而更加独立。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68582840"></a>13.2.1. UHCI</h3></div></div></div><a·id="idp68583480"·class="indexterm"></a><p>UHCI主控器维护着带有1024个指向每帧数据结构的帧列表。 | 5958 | ······完成很多工作,从而更加独立。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68550072"></a>13.2.1. UHCI</h3></div></div></div><a·id="idp68550712"·class="indexterm"></a><p>UHCI主控器维护着带有1024个指向每帧数据结构的帧列表。 |
5959 | ········它理解两种不同的数据类型:传输描述符(TD)和队列头(QH)。每个 | 5959 | ········它理解两种不同的数据类型:传输描述符(TD)和队列头(QH)。每个 |
5960 | » TD表示表示与设备端点进行通信的一个包。QH是将一些TD(和QH)划分 | 5960 | » TD表示表示与设备端点进行通信的一个包。QH是将一些TD(和QH)划分 |
5961 | » 成组的一种方法。</p><p>每个传输由一个或多个包组成。UHCI驱动程序将大的传输分割成 | 5961 | » 成组的一种方法。</p><p>每个传输由一个或多个包组成。UHCI驱动程序将大的传输分割成 |
5962 | ········多个包。除同步传输外,每个传输都会分配一个QH。对于每种类型的 | 5962 | ········多个包。除同步传输外,每个传输都会分配一个QH。对于每种类型的 |
5963 | » 传输,都有一个与此类型对应的QH,所有这些QH都会被集中到这个QH上。 | 5963 | » 传输,都有一个与此类型对应的QH,所有这些QH都会被集中到这个QH上。 |
5964 | » 由于有固定的时延需求,同步传输必须首先执行,它是通过帧列表中的 | 5964 | » 由于有固定的时延需求,同步传输必须首先执行,它是通过帧列表中的 |
5965 | » 指针直接引用的。最后的同步TD传输引用那一帧的中断传输的QH。中断 | 5965 | » 指针直接引用的。最后的同步TD传输引用那一帧的中断传输的QH。中断 |
Offset 5974, 15 lines modified | Offset 5974, 15 lines modified |
5974 | » 产生不同类型的中断。在传输的最后一个TD中,HC驱动程序设置 | 5974 | » 产生不同类型的中断。在传输的最后一个TD中,HC驱动程序设置 |
5975 | » Interrupt-On-Completion位来标记传输完成时的一个中断。如果TD达到了 | 5975 | » Interrupt-On-Completion位来标记传输完成时的一个中断。如果TD达到了 |
5976 | » 其最大错误数,就标记错误中断。如果在TD中设置短包侦测位,且传输了 | 5976 | » 其最大错误数,就标记错误中断。如果在TD中设置短包侦测位,且传输了 |
5977 | » 小于所设置的包长度(的包),就会标记此中断以通知控制器驱动程序传输 | 5977 | » 小于所设置的包长度(的包),就会标记此中断以通知控制器驱动程序传输 |
5978 | ········已完成。找出哪个传输已完成或产生错误是主控器驱动程序的任务。 | 5978 | ········已完成。找出哪个传输已完成或产生错误是主控器驱动程序的任务。 |
5979 | » 当中断服务例程被调用时,它将定位所有已完成的传输并调用它们的回调。 | 5979 | » 当中断服务例程被调用时,它将定位所有已完成的传输并调用它们的回调。 |
5980 | ········</p><p>更详尽的描述请看·<a·class="link"·href="http://developer.intel.com/design/USB/UHCI11D.htm"·target="_top">UHCI | 5980 | ········</p><p>更详尽的描述请看·<a·class="link"·href="http://developer.intel.com/design/USB/UHCI11D.htm"·target="_top">UHCI |
5981 | ········specification。</a></p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68586296"></a>13.2.2. OHCI</h3></div></div></div><a·id="idp68586936"·class="indexterm"></a><p>对OHCI主控器进行编程要容易得多。控制器假设有一组端点(endpoint)可用, | 5981 | ········specification。</a></p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68553528"></a>13.2.2. OHCI</h3></div></div></div><a·id="idp68554168"·class="indexterm"></a><p>对OHCI主控器进行编程要容易得多。控制器假设有一组端点(endpoint)可用, |
5982 | ········并知道帧中不同传输类型的调度优先级和排序。主控器使用的主要 | 5982 | ········并知道帧中不同传输类型的调度优先级和排序。主控器使用的主要 |
5983 | » 数据结构是端点描述符(ED),它上面连接着一个传输描述符(TD)的队列。 | 5983 | » 数据结构是端点描述符(ED),它上面连接着一个传输描述符(TD)的队列。 |
5984 | » ED包含端点所允许的最大的包大小,控制器硬件完成包的分割。每次传输 | 5984 | » ED包含端点所允许的最大的包大小,控制器硬件完成包的分割。每次传输 |
5985 | » 后都会更新指向数据缓冲区的指针,当起始和终止指针相等时,TD就退归 | 5985 | » 后都会更新指向数据缓冲区的指针,当起始和终止指针相等时,TD就退归 |
5986 | » 到完成队列(done-queue)。四种类型的端点各有其自己的队列。控制和 | 5986 | » 到完成队列(done-queue)。四种类型的端点各有其自己的队列。控制和 |
5987 | » 大块(bulk)端点分别在它们自己的队列排队。中断ED在树中排队,在树中的深度 | 5987 | » 大块(bulk)端点分别在它们自己的队列排队。中断ED在树中排队,在树中的深度 |
5988 | » 定义了它们运行的频度。</p><p>帧列表·中断·同步(isochronous)·控制·大块(bulk)</p><p>主控器在每帧中运行的调度看起来如下。控制器首先运行非 | 5988 | » 定义了它们运行的频度。</p><p>帧列表·中断·同步(isochronous)·控制·大块(bulk)</p><p>主控器在每帧中运行的调度看起来如下。控制器首先运行非 |
Offset 5992, 15 lines modified | Offset 5992, 15 lines modified |
5992 | » 遍历。同步TD包含了传输应当运行其中的第一个帧的帧编号。所有周期 | 5992 | » 遍历。同步TD包含了传输应当运行其中的第一个帧的帧编号。所有周期 |
5993 | » 性的传输运行过以后,控制和大块队列再次被遍历。中断服务例程会被 | 5993 | » 性的传输运行过以后,控制和大块队列再次被遍历。中断服务例程会被 |
5994 | » 周期性地调用,来处理完成的队列,为每个传输调用回调,并重新调度 | 5994 | » 周期性地调用,来处理完成的队列,为每个传输调用回调,并重新调度 |
5995 | » 中断和同步端点。</p><p>更详尽的描述请看·<a·class="link"·href="http://www.compaq.com/productinfo/development/openhci.html"·target="_top"> | 5995 | » 中断和同步端点。</p><p>更详尽的描述请看·<a·class="link"·href="http://www.compaq.com/productinfo/development/openhci.html"·target="_top"> |
5996 | ········OHCI·specification</a>。服务层,即中间层,提供了以可控的方式 | 5996 | ········OHCI·specification</a>。服务层,即中间层,提供了以可控的方式 |
5997 | » 对设备进行访问,并维护着由不同驱动程序和服务层所使用的资源。 | 5997 | » 对设备进行访问,并维护着由不同驱动程序和服务层所使用的资源。 |
5998 | ········此层处理下面几方面:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>设备配置信息</p></li><li·class="listitem"><p>与设备进行通信的管道</p></li><li·class="listitem"><p>探测和连接设备,以及从设备分离(detach)。 | 5998 | ········此层处理下面几方面:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>设备配置信息</p></li><li·class="listitem"><p>与设备进行通信的管道</p></li><li·class="listitem"><p>探测和连接设备,以及从设备分离(detach)。 |
5999 | ··» ··</p></li></ul></div></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="usb-dev"></a>13.3. USB设备信息</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68592696"></a>13.3.1. 设备配置信息</h3></div></div></div><p>每个设备提供了不同级别的配置信息。每个设备具有一个或多个 | 5999 | ··» ··</p></li></ul></div></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="usb-dev"></a>13.3. USB设备信息</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68559928"></a>13.3.1. 设备配置信息</h3></div></div></div><p>每个设备提供了不同级别的配置信息。每个设备具有一个或多个 |
6000 | ········配置,探测/连接期间从其中选定一个。配置提供功率和带宽要求。 | 6000 | ········配置,探测/连接期间从其中选定一个。配置提供功率和带宽要求。 |
6001 | » 每个配置中可以有多个接口。设备接口是端点的汇集(collection)。 | 6001 | » 每个配置中可以有多个接口。设备接口是端点的汇集(collection)。 |
6002 | » 例如,USB扬声器可以有一个音频接口(音频类),和对旋钮(knob)、 | 6002 | » 例如,USB扬声器可以有一个音频接口(音频类),和对旋钮(knob)、 |
6003 | ········拨号盘(dial)和按钮的接口(HID类)。 | 6003 | ········拨号盘(dial)和按钮的接口(HID类)。 |
6004 | ········一个配置中的所有接口可以同时有效,并可被不同的 | 6004 | ········一个配置中的所有接口可以同时有效,并可被不同的 |
6005 | » 驱动程序连接。每个接口可以有备用接口,以提供不同质量的服务参数。 | 6005 | » 驱动程序连接。每个接口可以有备用接口,以提供不同质量的服务参数。 |
6006 | » 例如,在照相机中,这用来提供不同的帧大小以及每秒帧数。</p><p>每个接口中可以指定0或多个端点。端点是与设备进行通信的单向 | 6006 | » 例如,在照相机中,这用来提供不同的帧大小以及每秒帧数。</p><p>每个接口中可以指定0或多个端点。端点是与设备进行通信的单向 |
Offset 6052, 15 lines modified | Offset 6052, 15 lines modified |
6052 | » 管道的某些支持。当传输期间出现错误,或者由于,例如缺乏缓冲区空间 | 6052 | » 管道的某些支持。当传输期间出现错误,或者由于,例如缺乏缓冲区空间 |
6053 | » 来存储进入的数据而引起的设备否定应答包(NAK)时,控制、大块和中断 | 6053 | » 来存储进入的数据而引起的设备否定应答包(NAK)时,控制、大块和中断 |
6054 | » 管道中的包会被重试。而同步包在传递失败或对包NAK时不会重试,因为 | 6054 | » 管道中的包会被重试。而同步包在传递失败或对包NAK时不会重试,因为 |
6055 | » 那样可能违反同步约束。</p></li></ul></div><p>所需带宽的可用性在管道的创建期间被计算。传输在1毫秒的帧内 | 6055 | » 那样可能违反同步约束。</p></li></ul></div><p>所需带宽的可用性在管道的创建期间被计算。传输在1毫秒的帧内 |
6056 | ········进行调度。帧中的带宽分配由USB规范的第5.6节规定。同步和中断传输被 | 6056 | ········进行调度。帧中的带宽分配由USB规范的第5.6节规定。同步和中断传输被 |
6057 | » 允许消耗帧中多达90%的带宽。控制和大块传输的包在所有同步和中断包 | 6057 | » 允许消耗帧中多达90%的带宽。控制和大块传输的包在所有同步和中断包 |
6058 | ········之后进行调度,并将消耗所有剩余带宽。</p><p>关于传输调度和带宽回收的更多信息可以在USB规范[2]的第5章, | 6058 | ········之后进行调度,并将消耗所有剩余带宽。</p><p>关于传输调度和带宽回收的更多信息可以在USB规范[2]的第5章, |
6059 | ········UHCI规范[3]的的第1.3节,OHCI规范[4]的3.4.2节中找到。</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="usb-devprobe"></a>13.4. 设备的探测和连接</h2></div></div></div><a·id="idp68604728"·class="indexterm"></a><p>集中器(hub)通知新设备已连接后,服务层给端口加电(switch·on), | 6059 | ········UHCI规范[3]的的第1.3节,OHCI规范[4]的3.4.2节中找到。</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="usb-devprobe"></a>13.4. 设备的探测和连接</h2></div></div></div><a·id="idp68596536"·class="indexterm"></a><p>集中器(hub)通知新设备已连接后,服务层给端口加电(switch·on), |
6060 | ······为设备提供100mA的电流。 | 6060 | ······为设备提供100mA的电流。 |
6061 | ······此时设备处于其默认状态,并监听设备地址0。服务层会通过默认 | 6061 | ······此时设备处于其默认状态,并监听设备地址0。服务层会通过默认 |
6062 | ······管道继续检取各种描述符。此后它将向设备发送Set·Address请求,将设备 | 6062 | ······管道继续检取各种描述符。此后它将向设备发送Set·Address请求,将设备 |
6063 | ······从默认设备地址(地址0)移开。可能有多个设备驱动程序支持此设备。例如, | 6063 | ······从默认设备地址(地址0)移开。可能有多个设备驱动程序支持此设备。例如, |
6064 | ······一个调制解调器可能通过AT兼容接口支持ISDN·TA。然而,特定型号的ISDN | 6064 | ······一个调制解调器可能通过AT兼容接口支持ISDN·TA。然而,特定型号的ISDN |
6065 | ······适配器的驱动程序可能提供对此设备的更好支持。为了支持这样的灵活性, | 6065 | ······适配器的驱动程序可能提供对此设备的更好支持。为了支持这样的灵活性, |
6066 | ······探测会返回优先级,指示他们的支持级别。支持产品的特定版本会具有最高 | 6066 | ······探测会返回优先级,指示他们的支持级别。支持产品的特定版本会具有最高 |
Offset 6071, 15 lines modified | Offset 6071, 15 lines modified |
6071 | ······在一个配置中连接到一个驱动程序。为了支持不同接口上使用多个驱动 | 6071 | ······在一个配置中连接到一个驱动程序。为了支持不同接口上使用多个驱动 |
6072 | ······程序的设备,探测会在一个配置中的所有尚未被驱动程序声明(claim)的 | 6072 | ······程序的设备,探测会在一个配置中的所有尚未被驱动程序声明(claim)的 |
6073 | ······接口上重复进行。超出集中器功率预算的配置会被忽略。连接期间,驱动 | 6073 | ······接口上重复进行。超出集中器功率预算的配置会被忽略。连接期间,驱动 |
6074 | ······程序应当把设备初始化到适当状态,但不能复位,因为那样会使得设备将 | 6074 | ······程序应当把设备初始化到适当状态,但不能复位,因为那样会使得设备将 |
6075 | ······它自己从总线上断开,并重新启动探测过程。为了避免消耗不必要的带宽, | 6075 | ······它自己从总线上断开,并重新启动探测过程。为了避免消耗不必要的带宽, |
6076 | ······不应当在连接时声明中断管道,而应当延迟分配管道,直到打开文件并真的 | 6076 | ······不应当在连接时声明中断管道,而应当延迟分配管道,直到打开文件并真的 |
6077 | ······使用数据。当关闭文件时,管道也应当被再次关闭,尽管设备可能仍然 | 6077 | ······使用数据。当关闭文件时,管道也应当被再次关闭,尽管设备可能仍然 |
6078 | ······连接着。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68606264"></a>13.4.1. 设备断开连接(disconnect)和分离(detach)</h3></div></div></div><a·id="idp68627384"·class="indexterm"></a><p>设备驱动程序与设备进行任何事务期间,应当预期会接收到错误。 | 6078 | ······连接着。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68598072"></a>13.4.1. 设备断开连接(disconnect)和分离(detach)</h3></div></div></div><a·id="idp68602808"·class="indexterm"></a><p>设备驱动程序与设备进行任何事务期间,应当预期会接收到错误。 |
6079 | ········USB的设计支持并鼓励设备在任何点及时断开连接。驱动程序应当确保 | 6079 | ········USB的设计支持并鼓励设备在任何点及时断开连接。驱动程序应当确保 |
6080 | » 当设备不在时做正确的事情。</p><p>此外,断开连接(disconnect)后又重新连接(reconnect)的设备不会 | 6080 | » 当设备不在时做正确的事情。</p><p>此外,断开连接(disconnect)后又重新连接(reconnect)的设备不会 |
6081 | ········被重新连接(reattach)为相同的设备实例。 | 6081 | ········被重新连接(reattach)为相同的设备实例。 |
6082 | ········将来当更多的设备支持序列号(参看设备描述符), | 6082 | ········将来当更多的设备支持序列号(参看设备描述符), |
6083 | » 或开发出其他定义设备标识的方法的时候,这种情况可能会改变。 | 6083 | » 或开发出其他定义设备标识的方法的时候,这种情况可能会改变。 |
6084 | » </p><p>设备断开连接是由集中器在传递到集中器驱动程序的中断包中发 | 6084 | » </p><p>设备断开连接是由集中器在传递到集中器驱动程序的中断包中发 |
6085 | ········信号通知(signal)的。状态改变信息指示哪个端口发现了连接改变。 | 6085 | ········信号通知(signal)的。状态改变信息指示哪个端口发现了连接改变。 |
Offset 6105, 48 lines modified | Offset 6105, 48 lines modified |
6105 | ······端点。监视器控制类也是如此。通过可用的内核和用户空间的库,与HID | 6105 | ······端点。监视器控制类也是如此。通过可用的内核和用户空间的库,与HID |
6106 | ······类驱动程序或通用驱动程序一起可以简单直接地创建对这些接口的支持。 | 6106 | ······类驱动程序或通用驱动程序一起可以简单直接地创建对这些接口的支持。 |
6107 | ······另一个设备可以作为在一个配置中的多个接口由不同的设备驱动程序驱动 | 6107 | ······另一个设备可以作为在一个配置中的多个接口由不同的设备驱动程序驱动 |
6108 | ······的例子,这个设备是一种便宜的键盘,带有老的鼠标接口。为了避免在 | 6108 | ······的例子,这个设备是一种便宜的键盘,带有老的鼠标接口。为了避免在 |
6109 | ······设备中为USB集中器包括一个硬件而导致的成本上升,制造商将从键盘背面的 | 6109 | ······设备中为USB集中器包括一个硬件而导致的成本上升,制造商将从键盘背面的 |
6110 | ······PS/2端口接收到的鼠标数据与来自键盘的按键组合成在同一个配置中的 | 6110 | ······PS/2端口接收到的鼠标数据与来自键盘的按键组合成在同一个配置中的 |
6111 | ······两个单独的接口。鼠标和键盘驱动程序各自连接到适当的接口,并分配到 | 6111 | ······两个单独的接口。鼠标和键盘驱动程序各自连接到适当的接口,并分配到 |
6112 | ······两个独立端点的管道.·</p><a·id="idp68632248"·class="indexterm"></a><p>例子:固件下载。已经开发出来的许多设备是基于通用目的处理器, | 6112 | ······两个独立端点的管道.·</p><a·id="idp68607672"·class="indexterm"></a><p>例子:固件下载。已经开发出来的许多设备是基于通用目的处理器, |
6113 | ······并将额外的USB核心加入其中。由于驱动程序的开发和USB设备的固件仍然 | 6113 | ······并将额外的USB核心加入其中。由于驱动程序的开发和USB设备的固件仍然 |
6114 | ······非常新,许多设备需要在连接(connect)之后下载固件。</p><p>下面的步骤非常简明直接。设备通过供应商和产品ID标识自身。第一 | 6114 | ······非常新,许多设备需要在连接(connect)之后下载固件。</p><p>下面的步骤非常简明直接。设备通过供应商和产品ID标识自身。第一 |
6115 | ······个驱动程序探测并连接到它,并将固件下载到其中。此后设备自己软复位, | 6115 | ······个驱动程序探测并连接到它,并将固件下载到其中。此后设备自己软复位, |
6116 | ······驱动程序分离。短暂的暂停之后设备宣布它在总线上的存在。设备将改变 | 6116 | ······驱动程序分离。短暂的暂停之后设备宣布它在总线上的存在。设备将改变 |
6117 | ······其供应商/产品/版本的ID以反映其提供有固件的事实,因此另一个驱动程序 | 6117 | ······其供应商/产品/版本的ID以反映其提供有固件的事实,因此另一个驱动程序 |
6118 | ······将探测它并连接(attach)到它。</p><p>这些类型的设备的一个例子是基于EZ-USB的ActiveWire·I/O板。这个 | 6118 | ······将探测它并连接(attach)到它。</p><p>这些类型的设备的一个例子是基于EZ-USB的ActiveWire·I/O板。这个 |
6119 | ······芯片有一个通用固件下载器。下载到ActiveWire板子上的固件改变版本ID。 | 6119 | ······芯片有一个通用固件下载器。下载到ActiveWire板子上的固件改变版本ID。 |
6120 | ······然后它将执行EZ-USB芯片的USB部分的软复位,从USB总线上断开,并再次 | 6120 | ······然后它将执行EZ-USB芯片的USB部分的软复位,从USB总线上断开,并再次 |
6121 | ······重新连接。</p><p>例子:大容量存储设备。对大容量存储设备的支持主要围绕现有的 | 6121 | ······重新连接。</p><p>例子:大容量存储设备。对大容量存储设备的支持主要围绕现有的 |
6122 | ······协议构建。Iomega·USB·Zip驱动器是基于SCSI版本的驱动器。SCSI命令和 | 6122 | ······协议构建。Iomega·USB·Zip驱动器是基于SCSI版本的驱动器。SCSI命令和 |
6123 | ······状态信息被包装到块中,在大块(bulk)管道上传输到/来自设备,在USB线 | 6123 | ······状态信息被包装到块中,在大块(bulk)管道上传输到/来自设备,在USB线 |
6124 | ······上模拟SCSI控制器。ATAPI和UFI命令以相似的方式被支持。</p><a·id="idp68634552"·class="indexterm"></a><p>大容量存储规范支持两种不同类型的对命令块的包装。最初的尝试 | 6124 | ······上模拟SCSI控制器。ATAPI和UFI命令以相似的方式被支持。</p><a·id="idp68609976"·class="indexterm"></a><p>大容量存储规范支持两种不同类型的对命令块的包装。最初的尝试 |
6125 | ······基于通过默认管道发送命令和状态信息,使用大块传输在host和设备之间 | 6125 | ······基于通过默认管道发送命令和状态信息,使用大块传输在host和设备之间 |
6126 | ······移动数据。在经验基础上设计出另一种方法,这种方法基于包装命令和 | 6126 | ······移动数据。在经验基础上设计出另一种方法,这种方法基于包装命令和 |
6127 | ······状态块,并在大块out和in端点上发送它们。规范精确地指定了何时必须 | 6127 | ······状态块,并在大块out和in端点上发送它们。规范精确地指定了何时必须 |
6128 | ······发生什么,以及在碰到错误条件的情况下应该做什么。为这些设备编写 | 6128 | ······发生什么,以及在碰到错误条件的情况下应该做什么。为这些设备编写 |
6129 | ······驱动程序的最大挑战是协调基于USB的协议,让它适合已有的对大容量存储设备 | 6129 | ······驱动程序的最大挑战是协调基于USB的协议,让它适合已有的对大容量存储设备 |
6130 | ······的支持。CAM提供了钩子,以相当直接了当的方式来完成这个。ATAPI就 | 6130 | ······的支持。CAM提供了钩子,以相当直接了当的方式来完成这个。ATAPI就 |
6131 | ······没有这么简单了,因为历史上IDE接口从未有过多种不同的表现方式。 | 6131 | ······没有这么简单了,因为历史上IDE接口从未有过多种不同的表现方式。 |
6132 | ······</p><p>来自Y-E·Data的对USB软盘的支持也不是那么直观,因为设计了一套 | 6132 | ······</p><p>来自Y-E·Data的对USB软盘的支持也不是那么直观,因为设计了一套 |
6133 | ······新的命令集。</p></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="newbus"></a>第 14 章 Newbus</h2></div><div><span·class="authorgroup">写作:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Jeroen</span>·<span·class="surname">Ruigrok·van·der·Werven·(asmodai)</span></span>·和·<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Hiten</span>·<span·class="surname">Pandya</span></span>.·</span></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#newbus-devdrivers">14.1.·设备驱动程序</a></span></dt><dt><span·class="sect1"><a·href="#newbus-overview">14.2.·Newbus概览</a></span></dt><dt><span·class="sect1"><a·href="#newbus-api">14.3.·Newbus·API</a></span></dt></dl></div><p><span·class="emphasis"><em>特别感谢Matthew·✂ | 6133 | ······新的命令集。</p></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="newbus"></a>第 14 章 Newbus</h2></div><div><span·class="authorgroup">写作:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Jeroen</span>·<span·class="surname">Ruigrok·van·der·Werven·(asmodai)</span></span>·和·<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Hiten</span>·<span·class="surname">Pandya</span></span>.·</span></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#newbus-devdrivers">14.1.·设备驱动程序</a></span></dt><dt><span·class="sect1"><a·href="#newbus-overview">14.2.·Newbus概览</a></span></dt><dt><span·class="sect1"><a·href="#newbus-api">14.3.·Newbus·API</a></span></dt></dl></div><p><span·class="emphasis"><em>特别感谢Matthew·✂ |
6134 | ··Doug·Rabson,·Mike·Smith,·Peter·Wemm·and·Scott·Long</em></span>.</p><p>本章详细解释了Newbus设备框架。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="newbus-devdrivers"></a>14.1. 设备驱动程序</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68664504"></a>14.1.1. 设备驱动程序的目的</h3></div></div></div><a·id="idp68665144"·class="indexterm"></a><a·id="idp68665656"·class="indexterm"></a><p>设备驱动程序是软件组件,它在内核关于外围设备(例如,磁盘、网络 | 6134 | ··Doug·Rabson,·Mike·Smith,·Peter·Wemm·and·Scott·Long</em></span>.</p><p>本章详细解释了Newbus设备框架。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="newbus-devdrivers"></a>14.1. 设备驱动程序</h2></div></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68635832"></a>14.1.1. 设备驱动程序的目的</h3></div></div></div><a·id="idp68636472"·class="indexterm"></a><a·id="idp68636984"·class="indexterm"></a><p>设备驱动程序是软件组件,它在内核关于外围设备(例如,磁盘、网络 |
6135 | ······适配卡)的通用视图和外围设备的实际实现之间提供了接口。 | 6135 | ······适配卡)的通用视图和外围设备的实际实现之间提供了接口。 |
6136 | ······<span·class="emphasis"><em>设备驱动程序接口(DDI)</em></span>是内核与设备驱动程序组件 | 6136 | ······<span·class="emphasis"><em>设备驱动程序接口(DDI)</em></span>是内核与设备驱动程序组件 |
6137 | ······之间定义的接口。 | 6137 | ······之间定义的接口。 |
6138 | ······</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68667320"></a>14.1.2. 设备驱动程序的类型</h3></div></div></div><p>在<span·class="trademark">UNIX</span>®那个时代,FreeBSD也从中延续而来,定义了四种类型的 | 6138 | ······</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68638648"></a>14.1.2. 设备驱动程序的类型</h3></div></div></div><p>在<span·class="trademark">UNIX</span>®那个时代,FreeBSD也从中延续而来,定义了四种类型的 |
6139 | ······设备:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>块设备驱动程序</p></li><li·class="listitem"><p>字符设备驱动程序</p></li><li·class="listitem"><p>网络设备驱动程序</p></li><li·class="listitem"><p>伪设备驱动程序</p></li></ul></div><a·id="idp68671288"·class="indexterm"></a><p><span·class="emphasis"><em>块设备</em></span>以使用固定大小的[数据]块的方式运行。 | 6139 | ······设备:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>块设备驱动程序</p></li><li·class="listitem"><p>字符设备驱动程序</p></li><li·class="listitem"><p>网络设备驱动程序</p></li><li·class="listitem"><p>伪设备驱动程序</p></li></ul></div><a·id="idp68642616"·class="indexterm"></a><p><span·class="emphasis"><em>块设备</em></span>以使用固定大小的[数据]块的方式运行。 |
6140 | ······这种类型的驱动程序依赖所谓的 | 6140 | ······这种类型的驱动程序依赖所谓的 |
6141 | ······<span·class="emphasis"><em>缓冲区缓存(buffer·cache)</em></span>,其目的 | 6141 | ······<span·class="emphasis"><em>缓冲区缓存(buffer·cache)</em></span>,其目的 |
6142 | ······是在内存中的专用区域缓存访问过的数据块。这种缓冲区缓存常常基于后台写 | 6142 | ······是在内存中的专用区域缓存访问过的数据块。这种缓冲区缓存常常基于后台写 |
6143 | ······(write-behind),这意味着数据在内存中被修改后,当系统进行其周期性 | 6143 | ······(write-behind),这意味着数据在内存中被修改后,当系统进行其周期性 |
6144 | ······磁盘刷新时才会被同步到磁盘,从而优化写操作。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68672952"></a>14.1.3. 字符设备</h3></div></div></div><a·id="idp68673592"·class="indexterm"></a><p>然而,在FreeBSD·4.0版本以及后续版本中, | 6144 | ······磁盘刷新时才会被同步到磁盘,从而优化写操作。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68644280"></a>14.1.3. 字符设备</h3></div></div></div><a·id="idp68644920"·class="indexterm"></a><p>然而,在FreeBSD·4.0版本以及后续版本中, |
6145 | ······块设备和字符设备的区别变得不存在了。</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="newbus-overview"></a>14.2. Newbus概览</h2></div></div></div><a·id="idp68675896"·class="indexterm"></a><p><span·class="emphasis"><em>Newbus</em></span>实现了一种基于抽象层的新型总线结构, | 6145 | ······块设备和字符设备的区别变得不存在了。</p></div></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="newbus-overview"></a>14.2. Newbus概览</h2></div></div></div><a·id="idp68647224"·class="indexterm"></a><p><span·class="emphasis"><em>Newbus</em></span>实现了一种基于抽象层的新型总线结构, |
6146 | ····可以在FreeBSD·3.0中看到这种总线结构的介绍,当时Alpha的移植被导入到 | 6146 | ····可以在FreeBSD·3.0中看到这种总线结构的介绍,当时Alpha的移植被导入到 |
6147 | ····代码树中。直到4.0它才成为设备驱动程序使用的默认系统。其目的是为主机 | 6147 | ····代码树中。直到4.0它才成为设备驱动程序使用的默认系统。其目的是为主机 |
6148 | ····系统提供给<span·class="emphasis"><em>操作系统</em></span>的各种总线和设备的互连提供更加 | 6148 | ····系统提供给<span·class="emphasis"><em>操作系统</em></span>的各种总线和设备的互连提供更加 |
6149 | ····面向对象的方法。</p><p>其主要特性包括:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>动态连接</p></li><li·class="listitem"><p>驱动程序容易模块化</p></li><li·class="listitem"><p>伪总线</p></li></ul></div><p>最显著的改变之一是从平面和特殊系统演变为设备树布局。</p><p>顶层驻留的是<span·class="emphasis"><em><span·class="quote">“<span·class="quote">根</span>”</span></em></span>设备,它作为 | 6149 | ····面向对象的方法。</p><p>其主要特性包括:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>动态连接</p></li><li·class="listitem"><p>驱动程序容易模块化</p></li><li·class="listitem"><p>伪总线</p></li></ul></div><p>最显著的改变之一是从平面和特殊系统演变为设备树布局。</p><p>顶层驻留的是<span·class="emphasis"><em><span·class="quote">“<span·class="quote">根</span>”</span></em></span>设备,它作为 |
6150 | ····父设备,所有其他设备挂接在它上面。对于每个结构,通常<span·class="quote">“<span·class="quote">根</span>”</span> | 6150 | ····父设备,所有其他设备挂接在它上面。对于每个结构,通常<span·class="quote">“<span·class="quote">根</span>”</span> |
6151 | ····只有单个孩子,其上连接着诸如<span·class="emphasis"><em>host-to-PCI桥</em></span> | 6151 | ····只有单个孩子,其上连接着诸如<span·class="emphasis"><em>host-to-PCI桥</em></span> |
6152 | ····等东西。对于x86,这种<span·class="quote">“<span·class="quote">根</span>”</span>设备为 | 6152 | ····等东西。对于x86,这种<span·class="quote">“<span·class="quote">根</span>”</span>设备为 |
Offset 6187, 15 lines modified | Offset 6187, 15 lines modified |
6187 | ····设备实现的一组相关的方法。</p><p>在Newbus系统中,设备方法是通过系统中的各种设备驱动程序提供的。当 | 6187 | ····设备实现的一组相关的方法。</p><p>在Newbus系统中,设备方法是通过系统中的各种设备驱动程序提供的。当 |
6188 | ····<span·class="emphasis"><em>自动配置(auto-configuration)</em></span>期间设备被连接(attach) | 6188 | ····<span·class="emphasis"><em>自动配置(auto-configuration)</em></span>期间设备被连接(attach) |
6189 | ····到驱动程序,它使用驱动程序声明的方法表。以后设备可以从其驱动程序 | 6189 | ····到驱动程序,它使用驱动程序声明的方法表。以后设备可以从其驱动程序 |
6190 | ····<span·class="emphasis"><em>分离(detach)</em></span>,并 | 6190 | ····<span·class="emphasis"><em>分离(detach)</em></span>,并 |
6191 | ····<span·class="emphasis"><em>重新连接(re-attach)</em></span>到具有新方法表的新驱动程序。这就 | 6191 | ····<span·class="emphasis"><em>重新连接(re-attach)</em></span>到具有新方法表的新驱动程序。这就 |
6192 | ····允许驱动程序的动态替换,而动态替换对于驱动程序的开发非常有用。</p><p>接口通过与文件系统中用于定义vnode操作的语言相似的接口定义语言来 | 6192 | ····允许驱动程序的动态替换,而动态替换对于驱动程序的开发非常有用。</p><p>接口通过与文件系统中用于定义vnode操作的语言相似的接口定义语言来 |
6193 | ····描述。接口被保存在方法文件中(通常命名为<code·class="filename">foo_if.m</code>)。 | 6193 | ····描述。接口被保存在方法文件中(通常命名为<code·class="filename">foo_if.m</code>)。 |
6194 | ····</p><div·class="example"><a·id="idp68714168"></a><div·class="example-title">例 14.1. Newbus的方法</div><div·class="example-contents"><pre·class="programlisting"> | 6194 | ····</p><div·class="example"><a·id="idp68681400"></a><div·class="example-title">例 14.1. Newbus的方法</div><div·class="example-contents"><pre·class="programlisting"> |
6195 | ······#·Foo·子系统/驱动程序(注释...) | 6195 | ······#·Foo·子系统/驱动程序(注释...) |
| |
6196 | » ··INTERFACE·foo | 6196 | » ··INTERFACE·foo |
| |
6197 | ·······» METHOD·int·doit·{ | 6197 | ·······» METHOD·int·doit·{ |
6198 | ·······» » device_t·dev; | 6198 | ·······» » device_t·dev; |
6199 | ·······» }; | 6199 | ·······» }; |
Offset 6219, 15 lines modified | Offset 6219, 15 lines modified |
6219 | ····<span·class="emphasis"><em><span·class="quote">“<span·class="quote">连接(attach)</span>”</span></em></span>和 | 6219 | ····<span·class="emphasis"><em><span·class="quote">“<span·class="quote">连接(attach)</span>”</span></em></span>和 |
6220 | ····<span·class="emphasis"><em><span·class="quote">“<span·class="quote">分离(detach)</span>”</span></em></span>,他们用来控制硬件的侦测, | 6220 | ····<span·class="emphasis"><em><span·class="quote">“<span·class="quote">分离(detach)</span>”</span></em></span>,他们用来控制硬件的侦测, |
6221 | ····以及<span·class="emphasis"><em><span·class="quote">“<span·class="quote">关闭(shutdown)</span>”</span></em></span>, | 6221 | ····以及<span·class="emphasis"><em><span·class="quote">“<span·class="quote">关闭(shutdown)</span>”</span></em></span>, |
6222 | ····<span·class="emphasis"><em><span·class="quote">“<span·class="quote">挂起(suspend)</span>”</span></em></span>和 | 6222 | ····<span·class="emphasis"><em><span·class="quote">“<span·class="quote">挂起(suspend)</span>”</span></em></span>和 |
6223 | ····<span·class="emphasis"><em><span·class="quote">“<span·class="quote">恢复(resume)</span>”</span></em></span>,他们用于关键事件通知。 | 6223 | ····<span·class="emphasis"><em><span·class="quote">“<span·class="quote">恢复(resume)</span>”</span></em></span>,他们用于关键事件通知。 |
6224 | ····</p><p>另一个,更加复杂接口是<span·class="emphasis"><em><span·class="quote">“<span·class="quote">bus</span>”</span></em></span>。 | 6224 | ····</p><p>另一个,更加复杂接口是<span·class="emphasis"><em><span·class="quote">“<span·class="quote">bus</span>”</span></em></span>。 |
6225 | ····此接口包含的方法适用于带有孩子的设备,包括访问总线特定的每设备信息 | 6225 | ····此接口包含的方法适用于带有孩子的设备,包括访问总线特定的每设备信息 |
6226 | ····<a·href="#ftn.idp68722872"·class="footnote"·id="idp68722872"><sup·class="footnote">[2]</sup></a>,事件通知 | 6226 | ····<a·href="#ftn.idp68694200"·class="footnote"·id="idp68694200"><sup·class="footnote">[2]</sup></a>,事件通知 |
6227 | ····(<span·class="emphasis"><em><code·class="literal">child_detached</code></em></span>, | 6227 | ····(<span·class="emphasis"><em><code·class="literal">child_detached</code></em></span>, |
6228 | ····<span·class="emphasis"><em><code·class="literal">driver_added</code></em></span>)和响应管理 | 6228 | ····<span·class="emphasis"><em><code·class="literal">driver_added</code></em></span>)和响应管理 |
6229 | ····(<span·class="emphasis"><em><code·class="literal">alloc_resource</code></em></span>, | 6229 | ····(<span·class="emphasis"><em><code·class="literal">alloc_resource</code></em></span>, |
6230 | ····<span·class="emphasis"><em><code·class="literal">activate_resource</code></em></span>, | 6230 | ····<span·class="emphasis"><em><code·class="literal">activate_resource</code></em></span>, |
6231 | ····<span·class="emphasis"><em><code·class="literal">deactivate_resource</code></em></span>, | 6231 | ····<span·class="emphasis"><em><code·class="literal">deactivate_resource</code></em></span>, |
6232 | ····<span·class="emphasis"><em><code·class="literal">release_resource</code></em></span>)。</p><p><span·class="quote">“<span·class="quote">bus</span>”</span>接口中的很多方法为总线设备的某些孩子执行服务。 | 6232 | ····<span·class="emphasis"><em><code·class="literal">release_resource</code></em></span>)。</p><p><span·class="quote">“<span·class="quote">bus</span>”</span>接口中的很多方法为总线设备的某些孩子执行服务。 |
6233 | ····这些方法通常使用前两个参量指定提供服务的总线和请求服务的子设备。为了 | 6233 | ····这些方法通常使用前两个参量指定提供服务的总线和请求服务的子设备。为了 |
Offset 6236, 51 lines modified | Offset 6236, 51 lines modified |
6236 | ····<code·class="literal">BUS_TEARDOWN_INTR(device_t·dev,·device_t·child,·...)</code> | 6236 | ····<code·class="literal">BUS_TEARDOWN_INTR(device_t·dev,·device_t·child,·...)</code> |
6237 | ····可以使用函数 | 6237 | ····可以使用函数 |
6238 | ····<code·class="literal">bus_teardown_intr(device_t·child,·...)</code>来调用。</p><p>系统中的某些总线类型提供了额外接口以提供对总线特定功能的访问。 | 6238 | ····<code·class="literal">bus_teardown_intr(device_t·child,·...)</code>来调用。</p><p>系统中的某些总线类型提供了额外接口以提供对总线特定功能的访问。 |
6239 | ····例如,PCI总线驱动程序定义了<span·class="quote">“<span·class="quote">pci</span>”</span>接口,此接口有两个方法 | 6239 | ····例如,PCI总线驱动程序定义了<span·class="quote">“<span·class="quote">pci</span>”</span>接口,此接口有两个方法 |
6240 | ····<span·class="emphasis"><em><code·class="literal">read_config</code></em></span>和 | 6240 | ····<span·class="emphasis"><em><code·class="literal">read_config</code></em></span>和 |
6241 | ····<span·class="emphasis"><em><code·class="literal">write_config</code></em></span>,用于访问PCI设备 | 6241 | ····<span·class="emphasis"><em><code·class="literal">write_config</code></em></span>,用于访问PCI设备 |
6242 | ····的配置寄存器。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="newbus-api"></a>14.3. Newbus·API</h2></div></div></div><p>由于Newbus·API非常庞大,本节努力将它文档化。本文档的下一版本会 | 6242 | ····的配置寄存器。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="newbus-api"></a>14.3. Newbus·API</h2></div></div></div><p>由于Newbus·API非常庞大,本节努力将它文档化。本文档的下一版本会 |
6243 | ····带来更多信息。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68736568"></a>14.3.1. 源代码目录树中的重要位置</h3></div></div></div><p><code·class="filename">src/sys/[arch]/[arch]</code>·-·特定机器结构的 | 6243 | ····带来更多信息。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68703800"></a>14.3.1. 源代码目录树中的重要位置</h3></div></div></div><p><code·class="filename">src/sys/[arch]/[arch]</code>·-·特定机器结构的 |
6244 | ······内核代码位于这个目录。例如<code·class="literal">i386</code>结构或 | 6244 | ······内核代码位于这个目录。例如<code·class="literal">i386</code>结构或 |
6245 | ······<code·class="literal">SPARC64</code>结构。</p><p><code·class="filename">src/sys/dev/[bus]</code>·-·支持特定 | 6245 | ······<code·class="literal">SPARC64</code>结构。</p><p><code·class="filename">src/sys/dev/[bus]</code>·-·支持特定 |
6246 | ······<code·class="literal">[bus]</code>的设备位于这个目录。</p><p><code·class="filename">src/sys/dev/pci</code>·-·PCI总线支持代码位于 | 6246 | ······<code·class="literal">[bus]</code>的设备位于这个目录。</p><p><code·class="filename">src/sys/dev/pci</code>·-·PCI总线支持代码位于 |
6247 | ······这个目录。</p><p><code·class="filename">src/sys/[isa|pci]</code>·-·PCI/ISA设备驱动程序 | 6247 | ······这个目录。</p><p><code·class="filename">src/sys/[isa|pci]</code>·-·PCI/ISA设备驱动程序 |
6248 | ······位于这个目录。FreeBSD<code·class="literal">4.0</code>版本中,PCI/ISA支持代码 | 6248 | ······位于这个目录。FreeBSD<code·class="literal">4.0</code>版本中,PCI/ISA支持代码 |
6249 | ······过去存在于这个目录中。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68741560"></a>14.3.2. 重要结构和类型定义</h3></div></div></div><p><code·class="literal">devclass_t</code>·-·这是指向 | 6249 | ······过去存在于这个目录中。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68708792"></a>14.3.2. 重要结构和类型定义</h3></div></div></div><p><code·class="literal">devclass_t</code>·-·这是指向 |
6250 | ······<code·class="literal">struct·devclass</code>的指针的类型定义。</p><p><code·class="literal">device_method_t</code>·-·与 | 6250 | ······<code·class="literal">struct·devclass</code>的指针的类型定义。</p><p><code·class="literal">device_method_t</code>·-·与 |
6251 | ······<code·class="literal">kobj_method_t</code>相同(参看 | 6251 | ······<code·class="literal">kobj_method_t</code>相同(参看 |
6252 | ······<code·class="filename">src/sys/kobj.h</code>)。</p><p><code·class="literal">device_t</code>·-·这是指向 | 6252 | ······<code·class="filename">src/sys/kobj.h</code>)。</p><p><code·class="literal">device_t</code>·-·这是指向 |
6253 | ······<code·class="literal">struct·device</code>的指针的类型定义。 | 6253 | ······<code·class="literal">struct·device</code>的指针的类型定义。 |
6254 | ······<code·class="literal">device_t</code>·表示系统中的设备。它是内核对象。 | 6254 | ······<code·class="literal">device_t</code>·表示系统中的设备。它是内核对象。 |
6255 | ······实现细节参看<code·class="filename">src/sys/sys/bus_private.h</code>。</p><p><code·class="literal">driver_t</code>·-·这是一个类型定义,它引用 | 6255 | ······实现细节参看<code·class="filename">src/sys/sys/bus_private.h</code>。</p><p><code·class="literal">driver_t</code>·-·这是一个类型定义,它引用 |
6256 | ······<code·class="literal">struct·driver</code>。 | 6256 | ······<code·class="literal">struct·driver</code>。 |
6257 | ······<code·class="literal">driver</code>结构是一类 | 6257 | ······<code·class="literal">driver</code>结构是一类 |
6258 | ······<code·class="literal">device(设备)</code>内核对象;它也保存着驱动程序的私有数据。 | 6258 | ······<code·class="literal">device(设备)</code>内核对象;它也保存着驱动程序的私有数据。 |
6259 | ······</p><div·class="figure"><a·id="idp68748216"></a><div·class="figure-title">图 14.1. <span·class="emphasis"><em>driver_t</em></span>实现</div><div·class="figure-contents"><pre·class="programlisting"> | 6259 | ······</p><div·class="figure"><a·id="idp68719544"></a><div·class="figure-title">图 14.1. <span·class="emphasis"><em>driver_t</em></span>实现</div><div·class="figure-contents"><pre·class="programlisting"> |
6260 | » ··struct·driver·{ | 6260 | » ··struct·driver·{ |
6261 | » ·····» KOBJ_CLASS_FIELDS; | 6261 | » ·····» KOBJ_CLASS_FIELDS; |
6262 | » ······» void» *priv;» » » /*·驱动程序私有数据·*/ | 6262 | » ······» void» *priv;» » » /*·驱动程序私有数据·*/ |
6263 | » ··}; | 6263 | » ··}; |
6264 | » </pre></div></div><br·class="figure-break"·/><p><code·class="literal">device_state_t</code>是一个枚举类型,即 | 6264 | » </pre></div></div><br·class="figure-break"·/><p><code·class="literal">device_state_t</code>是一个枚举类型,即 |
6265 | ······<code·class="literal">device_state</code>。它包含Newbus设备在自动配置前后 | 6265 | ······<code·class="literal">device_state</code>。它包含Newbus设备在自动配置前后 |
6266 | ······可能的状态。</p><div·class="figure"><a·id="idp68750648"></a><div·class="figure-title">图 14.2. 设备状态<span·class="emphasis"><em>device_state_t</em></span></div><div·class="figure-contents"><pre·class="programlisting"> | 6266 | ······可能的状态。</p><div·class="figure"><a·id="idp68721976"></a><div·class="figure-title">图 14.2. 设备状态<span·class="emphasis"><em>device_state_t</em></span></div><div·class="figure-contents"><pre·class="programlisting"> |
6267 | » ··/* | 6267 | » ··/* |
6268 | » ···*·src/sys/sys/bus.h | 6268 | » ···*·src/sys/sys/bus.h |
6269 | » ···*/ | 6269 | » ···*/ |
6270 | » ··typedef·enum·device_state·{ | 6270 | » ··typedef·enum·device_state·{ |
6271 | » ··» DS_NOTPRESENT,» /*·未探测或探测失败·*/ | 6271 | » ··» DS_NOTPRESENT,» /*·未探测或探测失败·*/ |
6272 | » ····» DS_ALIVE,» » /*·探测成功·*/ | 6272 | » ····» DS_ALIVE,» » /*·探测成功·*/ |
6273 | » ····» DS_ATTACHED,» /*·调用了连接方法·*/ | 6273 | » ····» DS_ATTACHED,» /*·调用了连接方法·*/ |
6274 | » ····» DS_BUSY»» » /*·设备已打开·*/ | 6274 | » ····» DS_BUSY»» » /*·设备已打开·*/ |
6275 | » ··}·device_state_t; | 6275 | » ··}·device_state_t; |
6276 | » </pre></div></div><br·class="figure-break"·/></div></div><div·class="footnotes"><br·/><hr·class="footnote-hr"·/><div·id="ftn.idp68722872"·class="footnote"><p><a·href="#idp68722872"·class="para"><sup·class="para">[2]·</sup></a><a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=bus_generic_read_ivar&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">bus_generic_read_ivar</span>(9)</span></a>·and | 6276 | » </pre></div></div><br·class="figure-break"·/></div></div><div·class="footnotes"><br·/><hr·class="footnote-hr"·/><div·id="ftn.idp68694200"·class="footnote"><p><a·href="#idp68694200"·class="para"><sup·class="para">[2]·</sup></a><a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=bus_generic_read_ivar&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">bus_generic_read_ivar</span>(9)</span></a>·and |
6277 | ····<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=bus_generic_write_ivar&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">bus_generic_write_ivar</span>(9)</span></a></p></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="oss"></a>第 15 章 声音子系统</h2></div><div><span·class="authorgroup">供稿:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Jean-Francois</span>·<span·class="surname">Dockes</span></span>.·</span></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#oss-intro">15.1.·简介</a></span></dt><dt><span·class="sect1"><a·href="#oss-files">15.2.·文件</a></span></dt><dt><span·class="sect1"><a·href="#pcm-probe-and-attach">15.3.·探测,连接等</a></span·✂ | 6277 | ····<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=bus_generic_write_ivar&sektion=9&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">bus_generic_write_ivar</span>(9)</span></a></p></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="oss"></a>第 15 章 声音子系统</h2></div><div><span·class="authorgroup">供稿:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"><span·class="firstname">Jean-Francois</span>·<span·class="surname">Dockes</span></span>.·</span></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#oss-intro">15.1.·简介</a></span></dt><dt><span·class="sect1"><a·href="#oss-files">15.2.·文件</a></span></dt><dt><span·class="sect1"><a·href="#pcm-probe-and-attach">15.3.·探测,连接等</a></span·✂ |
6278 | ······开来。这使得更容易加入对新设备的支持。</p><p>·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=pcm&sektion=4&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">pcm</span>(4)</span></a>框架是声音子系统的中心部分。它主要实现下面的组件: | 6278 | ······开来。这使得更容易加入对新设备的支持。</p><p>·<a·class="citerefentry"·href="http://www.FreeBSD.org/cgi/man.cgi?query=pcm&sektion=4&manpath=freebsd-release-ports"><span·class="citerefentry"><span·class="refentrytitle">pcm</span>(4)</span></a>框架是声音子系统的中心部分。它主要实现下面的组件: |
6279 | ······</p><a·id="idp68759224"·class="indexterm"></a><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>一个到数字化声音和混音器函数的系统调用接口(read,·write, | 6279 | ······</p><a·id="idp68730552"·class="indexterm"></a><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p>一个到数字化声音和混音器函数的系统调用接口(read,·write, |
6280 | ··········ioctls)。ioctl命令集合兼容老的<span·class="emphasis"><em>OSS</em></span> | 6280 | ··········ioctls)。ioctl命令集合兼容老的<span·class="emphasis"><em>OSS</em></span> |
6281 | » ··或<span·class="emphasis"><em>Voxware</em></span>接口,允许一般多媒体应用程序 | 6281 | » ··或<span·class="emphasis"><em>Voxware</em></span>接口,允许一般多媒体应用程序 |
6282 | » ··不加修改地移植。</p></li><li·class="listitem"><p>处理声音数据的公共代码(格式转换,虚拟通道)。</p></li><li·class="listitem"><p>一个统一的软件接口,与硬件特定的音频接口模块接口 | 6282 | » ··不加修改地移植。</p></li><li·class="listitem"><p>处理声音数据的公共代码(格式转换,虚拟通道)。</p></li><li·class="listitem"><p>一个统一的软件接口,与硬件特定的音频接口模块接口 |
6283 | ··········</p></li><li·class="listitem"><p>对某些通用硬件接口(ac97)或共享的硬件特定代码 | 6283 | ··········</p></li><li·class="listitem"><p>对某些通用硬件接口(ac97)或共享的硬件特定代码 |
6284 | » ··(例如:ISA·DMA例程)的额外支持。</p></li></ul></div><p>对特定声卡的支持是通过硬件特定的驱动程序来实现的,这些驱动程序 | 6284 | » ··(例如:ISA·DMA例程)的额外支持。</p></li></ul></div><p>对特定声卡的支持是通过硬件特定的驱动程序来实现的,这些驱动程序 |
6285 | ······提供通道和混音器接口,插入到通用<code·class="filename">pcm</code>代码中。 | 6285 | ······提供通道和混音器接口,插入到通用<code·class="filename">pcm</code>代码中。 |
6286 | ······</p><p>本章中,术语<code·class="filename">pcm</code>将指声音驱动程序的 | 6286 | ······</p><p>本章中,术语<code·class="filename">pcm</code>将指声音驱动程序的 |
Offset 6300, 15 lines modified | Offset 6300, 15 lines modified |
6300 | ··········设备私有结构<code·class="varname">struct·snddev_info</code>:</p><pre·class="programlisting">··········static·driver_t·xxx_driver·=·{ | 6300 | ··········设备私有结构<code·class="varname">struct·snddev_info</code>:</p><pre·class="programlisting">··········static·driver_t·xxx_driver·=·{ |
6301 | ··············"pcm", | 6301 | ··············"pcm", |
6302 | ··············xxx_methods, | 6302 | ··············xxx_methods, |
6303 | ··············sizeof(struct·snddev_info) | 6303 | ··············sizeof(struct·snddev_info) |
6304 | ··········}; | 6304 | ··········}; |
| |
6305 | ··········DRIVER_MODULE(snd_xxxpci,·pci,·xxx_driver,·pcm_devclass,·0,·0); | 6305 | ··········DRIVER_MODULE(snd_xxxpci,·pci,·xxx_driver,·pcm_devclass,·0,·0); |
6306 | ··········MODULE_DEPEND(snd_xxxpci,·snd_pcm,·PCM_MINVER,·PCM_PREFVER,PCM_MAXVER);</pre><a·id="idp68796216"·class="indexterm"></a><p>大多数声音驱动程序需要存储关于其设备的附加私有信息。私有数据 | 6306 | ··········MODULE_DEPEND(snd_xxxpci,·snd_pcm,·PCM_MINVER,·PCM_PREFVER,PCM_MAXVER);</pre><a·id="idp68747064"·class="indexterm"></a><p>大多数声音驱动程序需要存储关于其设备的附加私有信息。私有数据 |
6307 | ··········结构通常在连接例程中分配。其地址通过调用 | 6307 | ··········结构通常在连接例程中分配。其地址通过调用 |
6308 | ··········<code·class="function">pcm_register()</code>和 | 6308 | ··········<code·class="function">pcm_register()</code>和 |
6309 | ··········<code·class="function">mixer_init()</code>传递给 | 6309 | ··········<code·class="function">mixer_init()</code>传递给 |
6310 | ··········<code·class="filename">pcm</code>。后面<code·class="filename">pcm</code> | 6310 | ··········<code·class="filename">pcm</code>。后面<code·class="filename">pcm</code> |
6311 | ··········将此地址作为调用声音驱动程序接口时的参数传递回来。</p></li><li·class="listitem"><p>声音驱动程序的连接例程应当通过调用<code·class="function">mixer_init() | 6311 | ··········将此地址作为调用声音驱动程序接口时的参数传递回来。</p></li><li·class="listitem"><p>声音驱动程序的连接例程应当通过调用<code·class="function">mixer_init() |
6312 | ··········</code>向<code·class="filename">pcm</code>声明它的MIXER或AC97 | 6312 | ··········</code>向<code·class="filename">pcm</code>声明它的MIXER或AC97 |
6313 | ··········接口。对于MIXER接口,这会接着引起调用 | 6313 | ··········接口。对于MIXER接口,这会接着引起调用 |
Offset 6336, 20 lines modified | Offset 6336, 20 lines modified |
6336 | ····<code·class="function">device_shutdown</code>例程,这样电源管理和模块卸载就能 | 6336 | ····<code·class="function">device_shutdown</code>例程,这样电源管理和模块卸载就能 |
6337 | ····正确地发挥作用。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="oss-interfaces"></a>15.4. 接口</h2></div></div></div><p><code·class="filename">pcm</code>核心与声音驱动程序之间的接口以术语 | 6337 | ····正确地发挥作用。</p></div><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="oss-interfaces"></a>15.4. 接口</h2></div></div></div><p><code·class="filename">pcm</code>核心与声音驱动程序之间的接口以术语 |
6338 | ······<a·class="link"·href="#kernel-objects"·title="第 3 章 内核对象">内核对象</a>的叫法来定义。</p><p>声音驱动程序通常提供两种主要的接口: | 6338 | ······<a·class="link"·href="#kernel-objects"·title="第 3 章 内核对象">内核对象</a>的叫法来定义。</p><p>声音驱动程序通常提供两种主要的接口: |
6339 | ······<span·class="emphasis"><em>CHANNEL</em></span>以及 | 6339 | ······<span·class="emphasis"><em>CHANNEL</em></span>以及 |
6340 | ······<span·class="emphasis"><em>MIXER</em></span>或<span·class="emphasis"><em>AC97</em></span>。</p><p><span·class="emphasis"><em>AC97</em></span>是一个很小的硬件访问(寄存器读/写) | 6340 | ······<span·class="emphasis"><em>MIXER</em></span>或<span·class="emphasis"><em>AC97</em></span>。</p><p><span·class="emphasis"><em>AC97</em></span>是一个很小的硬件访问(寄存器读/写) |
6341 | ······接口,由驱动程序为带AC97编码解码器的硬件来实现。这种情况下,实际的 | 6341 | ······接口,由驱动程序为带AC97编码解码器的硬件来实现。这种情况下,实际的 |
6342 | ······MIXER接口由<code·class="filename">pcm</code>中共享的AC97代码提供。 | 6342 | ······MIXER接口由<code·class="filename">pcm</code>中共享的AC97代码提供。 |
6343 | ······</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68875576"></a>15.4.1. CHANNEL接口</h3></div></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68876216"></a>15.4.1.1. 函数参数的通常注意事项</h4></div></div></div><p>声音驱动程序通常用一个私有数据结构来描述他们的设备,驱动 | 6343 | ······</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68789560"></a>15.4.1. CHANNEL接口</h3></div></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68790200"></a>15.4.1.1. 函数参数的通常注意事项</h4></div></div></div><p>声音驱动程序通常用一个私有数据结构来描述他们的设备,驱动 |
6344 | » ··程序所支持的播放和录音数据通道各有一个。</p><p>对于所有的CHANNEL接口函数,第一个参数是一个不透明的指针。 | 6344 | » ··程序所支持的播放和录音数据通道各有一个。</p><p>对于所有的CHANNEL接口函数,第一个参数是一个不透明的指针。 |
6345 | » ··</p><p>第二个参数是指向私有的通道数据结构的指针, | 6345 | » ··</p><p>第二个参数是指向私有的通道数据结构的指针, |
6346 | ··········<code·class="function">channel_init()</code>是个例外,它的指针指向私有 | 6346 | ··········<code·class="function">channel_init()</code>是个例外,它的指针指向私有 |
6347 | » ··设备结构(并返回由<code·class="filename">pcm</code>以后使用的通道指针)。 | 6347 | » ··设备结构(并返回由<code·class="filename">pcm</code>以后使用的通道指针)。 |
6348 | » ··</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68211256"></a>15.4.1.2. 数据传输操作概览</h4></div></div></div><p>对于声音数据传输,<code·class="filename">pcm</code>核心与声音驱动 | 6348 | » ··</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68792888"></a>15.4.1.2. 数据传输操作概览</h4></div></div></div><p>对于声音数据传输,<code·class="filename">pcm</code>核心与声音驱动 |
6349 | » ··程序是通过一个由<code·class="varname">struct·snd_dbuf</code>描述的 | 6349 | » ··程序是通过一个由<code·class="varname">struct·snd_dbuf</code>描述的 |
6350 | » ··共享内存区域进行通信的。</p><p><code·class="varname">struct·snd_dbuf</code>是 | 6350 | » ··共享内存区域进行通信的。</p><p><code·class="varname">struct·snd_dbuf</code>是 |
6351 | ··········<code·class="filename">pcm</code>私有的,声音驱动程序通过调用访问者 | 6351 | ··········<code·class="filename">pcm</code>私有的,声音驱动程序通过调用访问者 |
6352 | » ··函数(<code·class="function">sndbuf_getxxx()</code>)来获得感兴趣的值。 | 6352 | » ··函数(<code·class="function">sndbuf_getxxx()</code>)来获得感兴趣的值。 |
6353 | » ··</p><p>共享内存区域的大小等于 | 6353 | » ··</p><p>共享内存区域的大小等于 |
6354 | ··········<code·class="function">sndbuf_getsize()</code>,并被分割为大小固定,且等于 | 6354 | ··········<code·class="function">sndbuf_getsize()</code>,并被分割为大小固定,且等于 |
6355 | ··········<code·class="function">sndbuf_getblksz()</code>字节的很多块。</p><p>当播放时,常规的传输机制如下(将意思反过来就是录音): | 6355 | ··········<code·class="function">sndbuf_getblksz()</code>字节的很多块。</p><p>当播放时,常规的传输机制如下(将意思反过来就是录音): |
Offset 6382, 31 lines modified | Offset 6382, 31 lines modified |
6382 | ··············<code·class="filename">pcm</code>通道控制结构的指针。这是个不透明 | 6382 | ··············<code·class="filename">pcm</code>通道控制结构的指针。这是个不透明 |
6383 | » ······指针。函数应当将它保存到局部通道结构中,在后面调用 | 6383 | » ······指针。函数应当将它保存到局部通道结构中,在后面调用 |
6384 | ··············<code·class="filename">pcm</code>函数(例如: | 6384 | ··············<code·class="filename">pcm</code>函数(例如: |
6385 | ··············<code·class="function">chn_intr(c)</code>)时会使用它。</p><p><code·class="varname">dir</code>指示通道方向 | 6385 | ··············<code·class="function">chn_intr(c)</code>)时会使用它。</p><p><code·class="varname">dir</code>指示通道方向 |
6386 | ··············(<code·class="literal">PCMDIR_PLAY</code>或 | 6386 | ··············(<code·class="literal">PCMDIR_PLAY</code>或 |
6387 | » ······<code·class="literal">PCMDIR_REC</code>)。</p></td></tr><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-chinit-return"><span><img·src="imagelib/callouts/2.png"·alt="2"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p>函数应当返回一个指针,此指针指向用于控制此通道的私有 | 6387 | » ······<code·class="literal">PCMDIR_REC</code>)。</p></td></tr><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-chinit-return"><span><img·src="imagelib/callouts/2.png"·alt="2"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p>函数应当返回一个指针,此指针指向用于控制此通道的私有 |
6388 | » ······区域。它将作为参数被传递到对其他通道接口的调用。 | 6388 | » ······区域。它将作为参数被传递到对其他通道接口的调用。 |
6389 | ··············</p></td></tr></table></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68884280"></a>15.4.1.4. channel_setformat</h4></div></div></div><p><code·class="function">xxxchannel_setformat()</code>应当按特定通道, | 6389 | ··············</p></td></tr></table></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68871992"></a>15.4.1.4. channel_setformat</h4></div></div></div><p><code·class="function">xxxchannel_setformat()</code>应当按特定通道, |
6390 | » ··特定声音格式设置硬件。</p><pre·class="programlisting">··········static·int | 6390 | » ··特定声音格式设置硬件。</p><pre·class="programlisting">··········static·int |
6391 | ··········xxxchannel_setformat(kobj_t·obj,·void·*data,·u_int32_t·format)<a·id="co-chsetformat-params"></a><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span> | 6391 | ··········xxxchannel_setformat(kobj_t·obj,·void·*data,·u_int32_t·format)<a·id="co-chsetformat-params"></a><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span> |
6392 | ··········{ | 6392 | ··········{ |
6393 | ··············struct·xxx_chinfo·*ch·=·data; | 6393 | ··············struct·xxx_chinfo·*ch·=·data; |
6394 | ···············... | 6394 | ···············... |
6395 | ··············return·0; | 6395 | ··············return·0; |
6396 | ···········}</pre><div·class="calloutlist"><table·border="0"·summary="Callout·list"><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-chsetformat-params"><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p><code·class="varname">format</code>为 | 6396 | ···········}</pre><div·class="calloutlist"><table·border="0"·summary="Callout·list"><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-chsetformat-params"><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p><code·class="varname">format</code>为 |
6397 | ··············<code·class="literal">AFMT_XXX·value</code>值之一 | 6397 | ··············<code·class="literal">AFMT_XXX·value</code>值之一 |
6398 | ··············(<code·class="filename">soundcard.h</code>)。</p></td></tr></table></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68888888"></a>15.4.1.5. channel_setspeed</h4></div></div></div><p><code·class="function">xxxchannel_setspeed()</code>按指定的取样速度 | 6398 | ··············(<code·class="filename">soundcard.h</code>)。</p></td></tr></table></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68254008"></a>15.4.1.5. channel_setspeed</h4></div></div></div><p><code·class="function">xxxchannel_setspeed()</code>按指定的取样速度 |
6399 | » ··设置通道硬件,并返回返回可能调整过的速度。</p><pre·class="programlisting">··········static·int | 6399 | » ··设置通道硬件,并返回返回可能调整过的速度。</p><pre·class="programlisting">··········static·int |
6400 | ··········xxxchannel_setspeed(kobj_t·obj,·void·*data,·u_int32_t·speed) | 6400 | ··········xxxchannel_setspeed(kobj_t·obj,·void·*data,·u_int32_t·speed) |
6401 | ··········{ | 6401 | ··········{ |
6402 | ··············struct·xxx_chinfo·*ch·=·data; | 6402 | ··············struct·xxx_chinfo·*ch·=·data; |
6403 | ···············... | 6403 | ···············... |
6404 | ··············return·speed; | 6404 | ··············return·speed; |
6405 | ···········}</pre></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68890680"></a>15.4.1.6. channel_setblocksize</h4></div></div></div><p><code·class="function">xxxchannel_setblocksize()</code>设置块大小, | 6405 | ···········}</pre></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68255800"></a>15.4.1.6. channel_setblocksize</h4></div></div></div><p><code·class="function">xxxchannel_setblocksize()</code>设置块大小, |
6406 | » ··这是<code·class="filename">pcm</code>与声音驱动程序,以及声音驱动 | 6406 | » ··这是<code·class="filename">pcm</code>与声音驱动程序,以及声音驱动 |
6407 | » ··程序与设备之间的传输单位的大小。传输期间,每次传输这样大小的 | 6407 | » ··程序与设备之间的传输单位的大小。传输期间,每次传输这样大小的 |
6408 | » ··数据后,声音驱动程序都应当调用<code·class="filename">pcm</code>的 | 6408 | » ··数据后,声音驱动程序都应当调用<code·class="filename">pcm</code>的 |
6409 | ··········<code·class="function">chn_intr()</code>。</p><p>大多数驱动程序只注意这儿的块大小,因为当实际传输开始时应该 | 6409 | ··········<code·class="function">chn_intr()</code>。</p><p>大多数驱动程序只注意这儿的块大小,因为当实际传输开始时应该 |
6410 | » ··使用这个值。</p><pre·class="programlisting">··········static·int | 6410 | » ··使用这个值。</p><pre·class="programlisting">··········static·int |
6411 | ··········xxxchannel_setblocksize(kobj_t·obj,·void·*data,·u_int32_t·blocksize) | 6411 | ··········xxxchannel_setblocksize(kobj_t·obj,·void·*data,·u_int32_t·blocksize) |
6412 | ··········{ | 6412 | ··········{ |
Offset 6431, 32 lines modified | Offset 6431, 32 lines modified |
6431 | » » ··基地址和大小。</p></li><li·class="listitem"><p><code·class="literal">PCMTRIG_EMLDMAWR</code>·/ | 6431 | » » ··基地址和大小。</p></li><li·class="listitem"><p><code·class="literal">PCMTRIG_EMLDMAWR</code>·/ |
6432 | ··················<code·class="literal">PCMTRIG_EMLDMARD</code>:告诉驱动程序, | 6432 | ··················<code·class="literal">PCMTRIG_EMLDMARD</code>:告诉驱动程序, |
6433 | » » ··输入或输出缓冲区可能已被更新过了。大多数驱动程序只是 | 6433 | » » ··输入或输出缓冲区可能已被更新过了。大多数驱动程序只是 |
6434 | » » ··忽略这些调用。</p></li><li·class="listitem"><p><code·class="literal">PCMTRIG_STOP</code>·/ | 6434 | » » ··忽略这些调用。</p></li><li·class="listitem"><p><code·class="literal">PCMTRIG_STOP</code>·/ |
6435 | ··················<code·class="literal">PCMTRIG_ABORT</code>:驱动程序应当停止当前 | 6435 | ··················<code·class="literal">PCMTRIG_ABORT</code>:驱动程序应当停止当前 |
6436 | » » ··的传输。</p></li></ul></div></td></tr></table></div><div·xmlns=""·class="note"><h3·class="admontitle">注意:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">如果驱动程序使用ISA·DMA,则应当在设备上执行动作前 | 6436 | » » ··的传输。</p></li></ul></div></td></tr></table></div><div·xmlns=""·class="note"><h3·class="admontitle">注意:·</h3><p·xmlns="http://www.w3.org/1999/xhtml">如果驱动程序使用ISA·DMA,则应当在设备上执行动作前 |
6437 | » ··调用<code·class="function">sndbuf_isadma()</code>,并处理DMA芯片一方的 | 6437 | » ··调用<code·class="function">sndbuf_isadma()</code>,并处理DMA芯片一方的 |
6438 | » ··事情。</p></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68906680"></a>15.4.1.8. channel_getptr</h4></div></div></div><p><code·class="function">xxxchannel_getptr()</code>返回传输缓冲区中 | 6438 | » ··事情。</p></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68873912"></a>15.4.1.8. channel_getptr</h4></div></div></div><p><code·class="function">xxxchannel_getptr()</code>返回传输缓冲区中 |
6439 | » ··当前的缓冲。它通常由<code·class="function">chn_intr()</code>调用,而且 | 6439 | » ··当前的缓冲。它通常由<code·class="function">chn_intr()</code>调用,而且 |
6440 | ··········这也是为什么<code·class="filename">pcm</code>知道它应当往哪儿传送 | 6440 | ··········这也是为什么<code·class="filename">pcm</code>知道它应当往哪儿传送 |
6441 | » ··新数据。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68908856"></a>15.4.1.9. channel_free</h4></div></div></div><p>调用<code·class="function">xxxchannel_free()</code>来释放通道资源, | 6441 | » ··新数据。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68876088"></a>15.4.1.9. channel_free</h4></div></div></div><p>调用<code·class="function">xxxchannel_free()</code>来释放通道资源, |
6442 | » ··例如当驱动程序卸载时,并且如果通道数据结构是动态分配的,或者 | 6442 | » ··例如当驱动程序卸载时,并且如果通道数据结构是动态分配的,或者 |
6443 | » ··如果不使用<code·class="function">sndbuf_alloc()</code>进行缓冲区分配, | 6443 | » ··如果不使用<code·class="function">sndbuf_alloc()</code>进行缓冲区分配, |
6444 | » ··则应当实现这个函数。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68910776"></a>15.4.1.10. channel_getcaps</h4></div></div></div><pre·class="programlisting">··········struct·pcmchan_caps·* | 6444 | » ··则应当实现这个函数。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68878008"></a>15.4.1.10. channel_getcaps</h4></div></div></div><pre·class="programlisting">··········struct·pcmchan_caps·* |
6445 | ··········xxxchannel_getcaps(kobj_t·obj,·void·*data) | 6445 | ··········xxxchannel_getcaps(kobj_t·obj,·void·*data) |
6446 | ··········{ | 6446 | ··········{ |
6447 | ··············return·&xxx_caps;<a·id="co-chgetcaps-return"></a><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span> | 6447 | ··············return·&xxx_caps;<a·id="co-chgetcaps-return"></a><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span> |
6448 | ···········}</pre><div·class="calloutlist"><table·border="0"·summary="Callout·list"><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-chgetcaps-return"><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p>这个例程返回指向(通常静态定义的) | 6448 | ···········}</pre><div·class="calloutlist"><table·border="0"·summary="Callout·list"><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-chgetcaps-return"><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p>这个例程返回指向(通常静态定义的) |
6449 | ··············<code·class="varname">pcmchan_caps</code>结构的指针(在 | 6449 | ··············<code·class="varname">pcmchan_caps</code>结构的指针(在 |
6450 | ··············<code·class="filename">sound/pcm/channel.h</code>中定义)。这个结构 | 6450 | ··············<code·class="filename">sound/pcm/channel.h</code>中定义)。这个结构 |
6451 | » ······保存着最小和最大采样频率和被接受的声音格式。任何声音驱动 | 6451 | » ······保存着最小和最大采样频率和被接受的声音格式。任何声音驱动 |
6452 | » ······程序都可以作为一个范例。</p></td></tr></table></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68279608"></a>15.4.1.11. 更多函数</h4></div></div></div><p><code·class="function">channel_reset()</code>, | 6452 | » ······程序都可以作为一个范例。</p></td></tr></table></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68881720"></a>15.4.1.11. 更多函数</h4></div></div></div><p><code·class="function">channel_reset()</code>, |
6453 | ··········<code·class="function">channel_resetdone()</code>和 | 6453 | ··········<code·class="function">channel_resetdone()</code>和 |
6454 | ··········<code·class="function">channel_notify()</code>用于特殊目的,未与权威人士 | 6454 | ··········<code·class="function">channel_notify()</code>用于特殊目的,未与权威人士 |
6455 | ··········(Cameron·Grant)进行探讨之前不应当在驱动程序中实现它。</p><p>不赞成使用<code·class="function">channel_setdir()</code>.</p></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68282808"></a>15.4.2. MIXER接口</h3></div></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="xxxmixer-init"></a>15.4.2.1. mixer_init</h4></div></div></div><p><code·class="function">xxxmixer_init()</code>初始化硬件,并告诉 | 6455 | ··········(Cameron·Grant)进行探讨之前不应当在驱动程序中实现它。</p><p>不赞成使用<code·class="function">channel_setdir()</code>.</p></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68884920"></a>15.4.2. MIXER接口</h3></div></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="xxxmixer-init"></a>15.4.2.1. mixer_init</h4></div></div></div><p><code·class="function">xxxmixer_init()</code>初始化硬件,并告诉 |
6456 | ··········<code·class="filename">pcm</code>什么混音器设备可用来播放和录音。 | 6456 | ··········<code·class="filename">pcm</code>什么混音器设备可用来播放和录音。 |
6457 | ··········</p><pre·class="programlisting">··········static·int | 6457 | ··········</p><pre·class="programlisting">··········static·int |
6458 | ··········xxxmixer_init(struct·snd_mixer·*m) | 6458 | ··········xxxmixer_init(struct·snd_mixer·*m) |
6459 | ··········{ | 6459 | ··········{ |
6460 | ··············struct·xxx_info···*sc·=·mix_getdevinfo(m); | 6460 | ··············struct·xxx_info···*sc·=·mix_getdevinfo(m); |
6461 | ··············u_int32_t·v; | 6461 | ··············u_int32_t·v; |
| |
Offset 6469, 59 lines modified | Offset 6469, 59 lines modified |
| |
6469 | ··············return·0; | 6469 | ··············return·0; |
6470 | ··········}</pre><div·class="calloutlist"><table·border="0"·summary="Callout·list"><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-mxini-sd"><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p>设置一个整数值中的位,并调用 | 6470 | ··········}</pre><div·class="calloutlist"><table·border="0"·summary="Callout·list"><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-mxini-sd"><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p>设置一个整数值中的位,并调用 |
6471 | ··············<code·class="function">mix_setdevs()</code>和 | 6471 | ··············<code·class="function">mix_setdevs()</code>和 |
6472 | ··············<code·class="function">mix_setrecdevs()</code>来告诉 | 6472 | ··············<code·class="function">mix_setrecdevs()</code>来告诉 |
6473 | ··············<code·class="filename">pcm</code>存在什么设备。</p></td></tr></table></div><p>混音器的位定义可以在<code·class="filename">soundcard.h</code>中 | 6473 | ··············<code·class="filename">pcm</code>存在什么设备。</p></td></tr></table></div><p>混音器的位定义可以在<code·class="filename">soundcard.h</code>中 |
6474 | » ··找到。(<code·class="literal">SOUND_MASK_XXX</code>值和 | 6474 | » ··找到。(<code·class="literal">SOUND_MASK_XXX</code>值和 |
6475 | ··········<code·class="literal">SOUND_MIXER_XXX</code>移位)。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68916792"></a>15.4.2.2. mixer_set</h4></div></div></div><p><code·class="function">xxxmixer_set()</code>为混音器设备设置音量级别 | 6475 | ··········<code·class="literal">SOUND_MIXER_XXX</code>移位)。</p></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68490808"></a>15.4.2.2. mixer_set</h4></div></div></div><p><code·class="function">xxxmixer_set()</code>为混音器设备设置音量级别 |
6476 | ··········(level)。</p><pre·class="programlisting">··········static·int | 6476 | ··········(level)。</p><pre·class="programlisting">··········static·int |
6477 | ··········xxxmixer_set(struct·snd_mixer·*m,·unsigned·dev, | 6477 | ··········xxxmixer_set(struct·snd_mixer·*m,·unsigned·dev, |
6478 | ···························unsigned·left,·unsigned·right)<a·id="co-mxset-params"></a><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span> | 6478 | ···························unsigned·left,·unsigned·right)<a·id="co-mxset-params"></a><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span> |
6479 | ··········{ | 6479 | ··········{ |
6480 | ··············struct·sc_info·*sc·=·mix_getdevinfo(m); | 6480 | ··············struct·sc_info·*sc·=·mix_getdevinfo(m); |
6481 | ··············[设置音量级别(level)] | 6481 | ··············[设置音量级别(level)] |
6482 | ··············return·left·|·(right·<<·8);<a·id="co-mxset-return"></a><span><img·src="imagelib/callouts/2.png"·alt="2"·border="0"·/></span> | 6482 | ··············return·left·|·(right·<<·8);<a·id="co-mxset-return"></a><span><img·src="imagelib/callouts/2.png"·alt="2"·border="0"·/></span> |
6483 | ··········}</pre><div·class="calloutlist"><table·border="0"·summary="Callout·list"><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-mxset-params"><span><img·src="imagelib/callouts/2.png"·alt="2"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p>由于硬件(音量)级别(level)可能不匹配输入比例,会出现 | 6483 | ··········}</pre><div·class="calloutlist"><table·border="0"·summary="Callout·list"><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-mxset-params"><span><img·src="imagelib/callouts/2.png"·alt="2"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p>由于硬件(音量)级别(level)可能不匹配输入比例,会出现 |
6484 | » ······某些圆整,例程返回如上面所示的实际级别值(范围0-100内)。</p></td></tr></table></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68922296"></a>15.4.2.3. mixer_setrecsrc</h4></div></div></div><p><code·class="function">xxxmixer_setrecsrc()</code>设定录音源设备。 | 6484 | » ······某些圆整,例程返回如上面所示的实际级别值(范围0-100内)。</p></td></tr></table></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68889528"></a>15.4.2.3. mixer_setrecsrc</h4></div></div></div><p><code·class="function">xxxmixer_setrecsrc()</code>设定录音源设备。 |
6485 | ··········</p><pre·class="programlisting">··········static·int | 6485 | ··········</p><pre·class="programlisting">··········static·int |
6486 | ··········xxxmixer_setrecsrc(struct·snd_mixer·*m,·u_int32_t·src)<a·id="co-mxsr-params"></a><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span> | 6486 | ··········xxxmixer_setrecsrc(struct·snd_mixer·*m,·u_int32_t·src)<a·id="co-mxsr-params"></a><span><img·src="imagelib/callouts/1.png"·alt="1"·border="0"·/></span> |
6487 | ··········{ | 6487 | ··········{ |
6488 | ··············struct·xxx_info·*sc·=·mix_getdevinfo(m); | 6488 | ··············struct·xxx_info·*sc·=·mix_getdevinfo(m); |
| |
6489 | ··············[查看src中的非零位,·设置硬件] | 6489 | ··············[查看src中的非零位,·设置硬件] |
| |
6490 | ··············[更新src反映实际动作] | 6490 | ··············[更新src反映实际动作] |
6491 | ··············return·src;<a·id="co-mxsr-return"></a><span><img·src="imagelib/callouts/2.png"·alt="2"·border="0"·/></span> | 6491 | ··············return·src;<a·id="co-mxsr-return"></a><span><img·src="imagelib/callouts/2.png"·alt="2"·border="0"·/></span> |
6492 | ···········}</pre><div·class="calloutlist"><table·border="0"·summary="Callout·list"><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-mxsr-params"><span><img·src="imagelib/callouts/2.png"·alt="2"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p>返回设置用来录音的实际设备。一些驱动程序只能设置一个 | 6492 | ···········}</pre><div·class="calloutlist"><table·border="0"·summary="Callout·list"><tr><td·width="5%"·valign="top"·align="left"><p><a·href="#co-mxsr-params"><span><img·src="imagelib/callouts/2.png"·alt="2"·border="0"·/></span></a>·</p></td><td·valign="top"·align="left"><p>返回设置用来录音的实际设备。一些驱动程序只能设置一个 |
6493 | » ······录音设备。如果出现错误,函数应当返回-1。</p></td></tr></table></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68927032"></a>15.4.2.4. mixer_uninit,·mixer_reinit</h4></div></div></div><p><code·class="function">xxxmixer_uninit()</code>应当确保不会发出任何 | 6493 | » ······录音设备。如果出现错误,函数应当返回-1。</p></td></tr></table></div></div><div·class="sect3"><div·xmlns=""·class="titlepage"><div><div><h4·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68894264"></a>15.4.2.4. mixer_uninit,·mixer_reinit</h4></div></div></div><p><code·class="function">xxxmixer_uninit()</code>应当确保不会发出任何 |
6494 | » ··声音,并且如果可能则应当让混音器硬件断电。</p><p><code·class="function">xxxmixer_reinit()</code>应当确保混音器硬件 | 6494 | » ··声音,并且如果可能则应当让混音器硬件断电。</p><p><code·class="function">xxxmixer_reinit()</code>应当确保混音器硬件 |
6495 | » ··加电,并且恢复所有不受<code·class="function">mixer_set()</code>或 | 6495 | » ··加电,并且恢复所有不受<code·class="function">mixer_set()</code>或 |
6496 | ··········<code·class="function">mixer_setrecsrc()</code>控制的设置。</p></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68929976"></a>15.4.3. AC97接口</h3></div></div></div><a·id="idp68930616"·class="indexterm"></a><p><span·class="emphasis"><em>AC97</em></span>由带有AC97编码解码器的驱动程序实现。 | 6496 | ··········<code·class="function">mixer_setrecsrc()</code>控制的设置。</p></div></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68897208"></a>15.4.3. AC97接口</h3></div></div></div><a·id="idp68897848"·class="indexterm"></a><p><span·class="emphasis"><em>AC97</em></span>由带有AC97编码解码器的驱动程序实现。 |
6497 | ········它只有三个方法:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><code·class="function">xxxac97_init()</code>返回找到的 | 6497 | ········它只有三个方法:</p><div·class="itemizedlist"><ul·class="itemizedlist"·style="list-style-type:·disc;·"><li·class="listitem"><p><code·class="function">xxxac97_init()</code>返回找到的 |
6498 | ··········ac97编码解码器的数目。</p></li><li·class="listitem"><p><code·class="function">ac97_read()</code>与 | 6498 | ··········ac97编码解码器的数目。</p></li><li·class="listitem"><p><code·class="function">ac97_read()</code>与 |
6499 | ··········<code·class="function">ac97_write()</code>读写指定的寄存器。</p></li></ul></div><p>The·<span·class="emphasis"><em>AC97</em></span>接口由 | 6499 | ··········<code·class="function">ac97_write()</code>读写指定的寄存器。</p></li></ul></div><p>The·<span·class="emphasis"><em>AC97</em></span>接口由 |
6500 | ········<code·class="filename">pcm</code>中的AC97代码来执行高层操作。参看 | 6500 | ········<code·class="filename">pcm</code>中的AC97代码来执行高层操作。参看 |
6501 | ········<code·class="filename">sound/pci/maestro3.c</code>或 | 6501 | ········<code·class="filename">sound/pci/maestro3.c</code>或 |
6502 | ········<code·class="filename">sound/pci/</code>下很多其他内容作为范例。</p></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="pccard"></a>第 16 章 PC·Card</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#pccard-adddev">16.1.·添加设备</a></span></dt></dl></div><a·id="idp68955448"·class="indexterm"></a><a·id="idp68955960"·class="indexterm"></a><p>本章将讨论FreeBSD为编写PC·Card或CardBus设备的驱动程序而提供的机制。 | 6502 | ········<code·class="filename">sound/pci/</code>下很多其他内容作为范例。</p></div></div></div><div·class="chapter"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="pccard"></a>第 16 章 PC·Card</h2></div><div><span·class="authorgroup">翻译:<span·xmlns="http://www.w3.org/1999/xhtml"·class="author"></span>.·</span></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="sect1"><a·href="#pccard-adddev">16.1.·添加设备</a></span></dt></dl></div><a·id="idp68906296"·class="indexterm"></a><a·id="idp68906808"·class="indexterm"></a><p>本章将讨论FreeBSD为编写PC·Card或CardBus设备的驱动程序而提供的机制。 |
6503 | ····但目前本文只记录了如何向现有的pccard驱动程序中添加驱动程序。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="pccard-adddev"></a>16.1. 添加设备</h2></div></div></div><p>向所支持的pccard设备列表中添加新设备的步骤已经与系统在FreeBSD·4 | 6503 | ····但目前本文只记录了如何向现有的pccard驱动程序中添加驱动程序。</p><div·class="sect1"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"·style="clear:·both"><a·id="pccard-adddev"></a>16.1. 添加设备</h2></div></div></div><p>向所支持的pccard设备列表中添加新设备的步骤已经与系统在FreeBSD·4 |
6504 | ······中使用的方法不同了。在以前的版本中,需要编辑 | 6504 | ······中使用的方法不同了。在以前的版本中,需要编辑 |
6505 | ······<code·class="filename">/etc</code>中的一个文件来列出设备。从FreeBSD·5.0开始, | 6505 | ······<code·class="filename">/etc</code>中的一个文件来列出设备。从FreeBSD·5.0开始, |
6506 | ······设备驱动程序知道它们支持什么设备。现在内核中有一个受支持设备的表, | 6506 | ······设备驱动程序知道它们支持什么设备。现在内核中有一个受支持设备的表, |
6507 | ······驱动程序用它来连接设备。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="pccard-overview"></a>16.1.1. 概览</h3></div></div></div><a·id="idp68406200"·class="indexterm"></a><p>可以有两种方法来识别PC·Card,他们都基于卡上的 | 6507 | ······驱动程序用它来连接设备。</p><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="pccard-overview"></a>16.1.1. 概览</h3></div></div></div><a·id="idp68910008"·class="indexterm"></a><p>可以有两种方法来识别PC·Card,他们都基于卡上的 |
6508 | ········<acronym·class="acronym">CIS</acronym>信息。第一种方法是使用制造商和产品的数字编号。 | 6508 | ········<acronym·class="acronym">CIS</acronym>信息。第一种方法是使用制造商和产品的数字编号。 |
6509 | ········第二种方法是使用人可读的字符串,字符串也是包含在CIS中。PC·Card总线 | 6509 | ········第二种方法是使用人可读的字符串,字符串也是包含在CIS中。PC·Card总线 |
6510 | ········使用集中式数据库和一些宏来提供一个易用的设计模式,让驱动程序的编写 | 6510 | ········使用集中式数据库和一些宏来提供一个易用的设计模式,让驱动程序的编写 |
6511 | ········者很容易地确定匹配其驱动程序的设备。</p><p>一个很普遍的实际情况是,某个公司为一款PC·Card产品开发出参考 | 6511 | ········者很容易地确定匹配其驱动程序的设备。</p><p>一个很普遍的实际情况是,某个公司为一款PC·Card产品开发出参考 |
6512 | ········设计,然后把这个设计卖给另外的公司,以便在市场上出售。那些公司改进 | 6512 | ········设计,然后把这个设计卖给另外的公司,以便在市场上出售。那些公司改进 |
6513 | ········原设计,把向他们的目标客户群或地理区域出售产品,并将他们自己的名字 | 6513 | ········原设计,把向他们的目标客户群或地理区域出售产品,并将他们自己的名字 |
6514 | ········放到卡中。然而所谓的对现有卡的改进,即使做过任何修改,这些修改通常 | 6514 | ········放到卡中。然而所谓的对现有卡的改进,即使做过任何修改,这些修改通常 |
6515 | ········也微乎其微。然而,为了强化他们自己版本的品牌,这些供货商常常会把他们 | 6515 | ········也微乎其微。然而,为了强化他们自己版本的品牌,这些供货商常常会把他们 |
6516 | ········公司的名字放入CIS空间的可读字符串中,却不会改动制造商和产品的ID。 | 6516 | ········公司的名字放入CIS空间的可读字符串中,却不会改动制造商和产品的ID。 |
6517 | ········</p><a·id="idp68407864"·class="indexterm"></a><a·id="idp68408376"·class="indexterm"></a><a·id="idp68408888"·class="indexterm"></a><p>鉴于以上情况,对于FreeBSD来说使用数字ID可以减小工作量。同时也 | 6517 | ········</p><a·id="idp68911672"·class="indexterm"></a><a·id="idp68912184"·class="indexterm"></a><a·id="idp68912696"·class="indexterm"></a><p>鉴于以上情况,对于FreeBSD来说使用数字ID可以减小工作量。同时也 |
6518 | ········会减小将ID加入到系统的过程中所带来的复杂性。必须仔细检查谁是卡的 | 6518 | ········会减小将ID加入到系统的过程中所带来的复杂性。必须仔细检查谁是卡的 |
6519 | ········真正制造者,尤其当提供原卡的供货商在中心数据库中已经有一个不同的ID | 6519 | ········真正制造者,尤其当提供原卡的供货商在中心数据库中已经有一个不同的ID |
6520 | ········时。Linksys,D-Link和NetGear是经常出售相同设计的几个美国制造商。 | 6520 | ········时。Linksys,D-Link和NetGear是经常出售相同设计的几个美国制造商。 |
6521 | ········相同的设计可能在日本以诸如Buffalo和Corega的名字出售。然而,这些 | 6521 | ········相同的设计可能在日本以诸如Buffalo和Corega的名字出售。然而,这些 |
6522 | ········设备常常具有相同的制造商和产品ID。</p><p>PC·Card总线在其中心数据库 | 6522 | ········设备常常具有相同的制造商和产品ID。</p><p>PC·Card总线在其中心数据库 |
6523 | ········<code·class="filename">/sys/dev/pccard/pccarddevs</code>中保存了卡的信息, | 6523 | ········<code·class="filename">/sys/dev/pccard/pccarddevs</code>中保存了卡的信息, |
6524 | ········但不包含哪个驱动程序与它们关联的信息。它也提供了一套宏,以允许在 | 6524 | ········但不包含哪个驱动程序与它们关联的信息。它也提供了一套宏,以允许在 |
Offset 6576, 15 lines modified | Offset 6576, 15 lines modified |
6576 | ········实际的空格。空条目意味着条目的这部分应当被忽略。在我选择的例子中 | 6576 | ········实际的空格。空条目意味着条目的这部分应当被忽略。在我选择的例子中 |
6577 | ········有一个错误的条目。除非对卡的操作来说至关重要,否则不应当在其中 | 6577 | ········有一个错误的条目。除非对卡的操作来说至关重要,否则不应当在其中 |
6578 | ········包含版本号。有时供货商在这个字段中会有卡的很多不同版本,这些版本 | 6578 | ········包含版本号。有时供货商在这个字段中会有卡的很多不同版本,这些版本 |
6579 | ········都能工作,这种情况下那些信息只会让那些拥有相似卡的人在FreeBSD中 | 6579 | ········都能工作,这种情况下那些信息只会让那些拥有相似卡的人在FreeBSD中 |
6580 | ········更难以使用。有时当供货商出于市场考虑(可用性,价格等等),希望出售 | 6580 | ········更难以使用。有时当供货商出于市场考虑(可用性,价格等等),希望出售 |
6581 | ········同一品牌下的很多不同部分时,这也是有必要的。如果这样,则在那些 | 6581 | ········同一品牌下的很多不同部分时,这也是有必要的。如果这样,则在那些 |
6582 | ········供货商仍然保持相同的制造商/产品对的少见情况下,能否区分开卡至关 | 6582 | ········供货商仍然保持相同的制造商/产品对的少见情况下,能否区分开卡至关 |
6583 | ········重要.·此时不能使用正则表达式匹配。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="pccard-probe"></a>16.1.3. 探测例程样例</h3></div></div></div><a·id="idp68990904"·class="indexterm"></a><p>要懂得如何向所支持的设备列表中添加设备,就必须懂得很多驱动程序 | 6583 | ········重要.·此时不能使用正则表达式匹配。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="pccard-probe"></a>16.1.3. 探测例程样例</h3></div></div></div><a·id="idp68929464"·class="indexterm"></a><p>要懂得如何向所支持的设备列表中添加设备,就必须懂得很多驱动程序 |
6584 | ········都有的探测和/或匹配例程。由于也为老卡提供了一个兼容层,这在 | 6584 | ········都有的探测和/或匹配例程。由于也为老卡提供了一个兼容层,这在 |
6585 | ········FreeBSD·5.x中有一点复杂。由于只是window-dressing不同,这儿给出了 | 6585 | ········FreeBSD·5.x中有一点复杂。由于只是window-dressing不同,这儿给出了 |
6586 | ········一个理想化的版本。</p><pre·class="programlisting">static·const·struct·pccard_product·wi_pccard_products[]·=·{ | 6586 | ········一个理想化的版本。</p><pre·class="programlisting">static·const·struct·pccard_product·wi_pccard_products[]·=·{ |
6587 | » PCMCIA_CARD(3COM,·3CRWE737A,·0), | 6587 | » PCMCIA_CARD(3COM,·3CRWE737A,·0), |
6588 | » PCMCIA_CARD(BUFFALO,·WLI_PCM_S11,·0), | 6588 | » PCMCIA_CARD(BUFFALO,·WLI_PCM_S11,·0), |
6589 | » PCMCIA_CARD(BUFFALO,·WLI_CF_S11G,·0), | 6589 | » PCMCIA_CARD(BUFFALO,·WLI_CF_S11G,·0), |
6590 | » PCMCIA_CARD(TDK,·LAK_CD011WL,·0), | 6590 | » PCMCIA_CARD(TDK,·LAK_CD011WL,·0), |
Offset 6667, 9 lines modified | Offset 6667, 9 lines modified |
6667 | ········$FreeBSD$标签会留在后面的文件中)。最后,你需要把 | 6667 | ········$FreeBSD$标签会留在后面的文件中)。最后,你需要把 |
6668 | ········其它东西提交到驱动程序。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="pccard-pr"></a>16.1.5. 提交新设备</h3></div></div></div><p>很多人直接把新设备的条目发送给作者。请不要那样做。请将它们作为 | 6668 | ········其它东西提交到驱动程序。</p></div><div·class="sect2"><div·xmlns=""·class="titlepage"><div><div><h3·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="pccard-pr"></a>16.1.5. 提交新设备</h3></div></div></div><p>很多人直接把新设备的条目发送给作者。请不要那样做。请将它们作为 |
6669 | ········PR来提交,并将PR号码发送给作者用于记录。这样确保条目不会丢失。提交 | 6669 | ········PR来提交,并将PR号码发送给作者用于记录。这样确保条目不会丢失。提交 |
6670 | ········PR时,补丁中没有必要包含<code·class="filename">pccardevs.h</code>的diff, | 6670 | ········PR时,补丁中没有必要包含<code·class="filename">pccardevs.h</code>的diff, |
6671 | ········因为那些东西可以重新产生。包含设备的描述和客户驱动程序的补丁是必要 | 6671 | ········因为那些东西可以重新产生。包含设备的描述和客户驱动程序的补丁是必要 |
6672 | ········的。如果你不知道名字,使用OEM99作为名字,作者将会调查后相应地调整 | 6672 | ········的。如果你不知道名字,使用OEM99作为名字,作者将会调查后相应地调整 |
6673 | ········OEM99。提交者不应当提交OEM99,而应该找到最高的OEM条目并提交高于那个 | 6673 | ········OEM99。提交者不应当提交OEM99,而应该找到最高的OEM条目并提交高于那个 |
6674 | ········的一个。</p></div></div></div></div><div·class="part"><div·xmlns=""·class="titlepage"><div><div><h1·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="appendices"></a>部分 III. 附录</h1></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="bibliography"><a·href="#idp69017912">参考书目</a></span></dt></dl></div><div·class="bibliography"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp69017912"></a>参考书目</h2></div></div></div><div·class="biblioentry"><a·id="idp69018168"></a><p>[1]·<span·class="authorgroup"><span·class="firstname">Marshall</span>·<span·class="othername">Kirk</span>·<span·class="surname">McKusick</span>、<span·class="firstname">Keith</span>·<span·class="surname">Bostic</span>、<span·class="firstname">Michael</span>·<span·class="othername">J</span>·<span·class="surname">Karels</span>和<span·class="firstname">John</span>·<span·class="othername">S</span>·<span·class="surname">Quarterman</span>.·</s·✂ | 6674 | ········的一个。</p></div></div></div></div><div·class="part"><div·xmlns=""·class="titlepage"><div><div><h1·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="appendices"></a>部分 III. 附录</h1></div></div></div><div·class="toc"><div·class="toc-title">目录</div><dl·class="toc"><dt><span·class="bibliography"><a·href="#idp68972856">参考书目</a></span></dt></dl></div><div·class="bibliography"><div·xmlns=""·class="titlepage"><div><div><h2·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68972856"></a>参考书目</h2></div></div></div><div·class="biblioentry"><a·id="idp68973112"></a><p>[1]·<span·class="authorgroup"><span·class="firstname">Marshall</span>·<span·class="othername">Kirk</span>·<span·class="surname">McKusick</span>、<span·class="firstname">Keith</span>·<span·class="surname">Bostic</span>、<span·class="firstname">Michael</span>·<span·class="othername">J</span>·<span·class="surname">Karels</span>和<span·class="firstname">John</span>·<span·class="othername">S</span>·<span·class="surname">Quarterman</span>.·</s·✂ |
6675 | ········Inc..·</span><span·class="biblioid">0-201-54979-4.·</span><span·class="publisher"><span·class="publishername">Addison-Wesley·Publishing·Company,·Inc..·</span></span><span·class="citetitle"><em·class="citetitle">The·Design·and·Implementation·of·the·4.4·BSD·Operating·System</em>.·</span><span·class="pagenums">1-2.·</span></p></div></div></div><div·class="index"><div·xmlns=""·class="titlepage"><div><div><h1·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp69030968"></a>索引</h1></div></div></div><div·class="index"><div·class="indexdiv"><h3>A</h3><dl><dt>AC97,<a·class="indexterm"·href="#idp68929976">AC97接口</a></dt><dt>ATAPI(AT·Attachment·Packet·Interface,·(IBM·PC)AT附属包接口),<a·class="indexterm"·href="#usb-protocol">USB驱动程序的协议信息</a></dt><dt>atomic·instructions(原子操作指令),<a·class="indexterm"·href="#idp67066424">原子操作指令和内存栅</a></dt><dt>atomic·operations(原子操作),<a·class="indexterm"·href="#locking">内核中的锁</a></dt><dt>atomically·protected·variables(原子保护变量),<a·class="indexterm"·href="#locking-atomic">原子保护变量</·✂ | 6675 | ········Inc..·</span><span·class="biblioid">0-201-54979-4.·</span><span·class="publisher"><span·class="publishername">Addison-Wesley·Publishing·Company,·Inc..·</span></span><span·class="citetitle"><em·class="citetitle">The·Design·and·Implementation·of·the·4.4·BSD·Operating·System</em>.·</span><span·class="pagenums">1-2.·</span></p></div></div></div><div·class="index"><div·xmlns=""·class="titlepage"><div><div><h1·xmlns="http://www.w3.org/1999/xhtml"·class="title"><a·id="idp68985912"></a>索引</h1></div></div></div><div·class="index"><div·class="indexdiv"><h3>A</h3><dl><dt>AC97,<a·class="indexterm"·href="#idp68897208">AC97接口</a></dt><dt>ATAPI(AT·Attachment·Packet·Interface,·(IBM·PC)AT附属包接口),<a·class="indexterm"·href="#usb-protocol">USB驱动程序的协议信息</a></dt><dt>atomic·instructions(原子操作指令),<a·class="indexterm"·href="#idp67066424">原子操作指令和内存栅</a></dt><dt>atomic·operations(原子操作),<a·class="indexterm"·href="#locking">内核中的锁</a></dt><dt>atomically·protected·variables(原子保护变量),<a·class="indexterm"·href="#locking-atomic">原子保护变量</·✂ |