📄 x429.html
字号:
CLASS="LITERAL"
>0xbffff978</TT
> 为偏移量的一块内存区域。绝大多数情况下,一个进程像普通的"Hello, World"不可以访问别的进程的内存空间,尽管有实现这种机制的方法。
我们将在以后讨论。.</P
><P
>内核自己也有内存空间。既然一个内核模块可以动态的从内核中加载和卸载,它其实是共享内核的内存空间而不是自己拥有
独立的内存空间。因此,一旦你的模块具有内存设计缺陷,内核就是内存设计缺陷了。如果你在错误的覆盖数据,那么你就在
破坏内核的代码。这比现在听起来的还糟。所以尽量小心谨慎。</P
><P
>顺便提一下,以上我所指出的对于任何单内核的操作系统都是真实的<A
NAME="AEN522"
HREF="#FTN.AEN522"
><SPAN
CLASS="footnote"
>[3]</SPAN
></A
>。也存在模块化微内核的操作系统。如 GNU Hurd 和 QNX Neutrino。</P
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN524"
></A
>3.1.6. 设备 驱动程序</H2
><P
>一种内核模块是设备驱动程序,为使用硬件设备像电视卡和串口而编写。在Unix中,任何设备都被当作路径 <TT
CLASS="FILENAME"
>/dev</TT
> 下的设备文件处理,并通过这些设备文件提供访问硬件的方法。 设备驱动为用户程序访问硬件设备。举例来说,声卡设备驱动程序 <TT
CLASS="FILENAME"
>es1370.o</TT
> 将会把设备文件 <TT
CLASS="FILENAME"
>/dev/sound</TT
> 同声卡硬件 Ensoniq IS1370 联系起来。这样用户程序像 mp3blaster 就可以通过访问设备文件 <TT
CLASS="FILENAME"
>/dev/sound</TT
> 运行而不必知道那种声卡硬件安装在系统上。</P
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="AEN532"
></A
>3.1.6.1. 主文件名和从文件名</H3
><P
>让我们来研究几个设备文件。这里的几个设备文件代表着一块主IDE硬盘上的头三个分区:</P
><TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
> # ls -l /dev/hda[1-3]
brw-rw---- 1 root disk 3, 1 Jul 5 2000 /dev/hda1
brw-rw---- 1 root disk 3, 2 Jul 5 2000 /dev/hda2
brw-rw---- 1 root disk 3, 3 Jul 5 2000 /dev/hda3
</PRE
></FONT
></TD
></TR
></TABLE
><P
>注意一下被逗号隔开的两列。第一个数字被叫做主设备号,第二个被叫做从设备号。主设备号决定使用何种设备驱动程序。
每种不同的设备都被分配了不同的主设备号;所有具有相同主设备号的设备文件都是被同一个驱动程序控制。上面例子中的
主设备号都为3,表示它们都被同一个驱动程序控制。
</P
><P
>从设备号用来区别驱动程序控制的多个设备。上面例子中的从设备号不相同是因为它们被识别为几个设备。</P
><P
> 设备被大概的分为两类:字符设备和块设备。区别是块设备有缓冲区,所以它们可以对请求进行优化排序。这对存储设备尤其
重要,因为读写相邻的文件总比读写相隔很远的文件要快。另一个区别是块设备输入和输出都是以数据块为单位的,但是字符设备
就可以自由读写任意量的字节。大部分硬件设备为字符设备,因为它们不需要缓冲区和数据不是按块来传输的。你可以通过命令 <B
CLASS="COMMAND"
>ls -l</B
>输出的头一个字母识别一个设备为何种设备。如果是'b' 就是块设备,如果是'c'就是字符设备。以上你看到的是块设备。这儿还有
一些字符设备文件(串口):</P
><TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
> crw-rw---- 1 root dial 4, 64 Feb 18 23:34 /dev/ttyS0
crw-r----- 1 root dial 4, 65 Nov 17 10:26 /dev/ttyS1
crw-rw---- 1 root dial 4, 66 Jul 5 2000 /dev/ttyS2
crw-rw---- 1 root dial 4, 67 Jul 5 2000 /dev/ttyS3
</PRE
></FONT
></TD
></TR
></TABLE
><P
> 如果你想看一下已分配的主设备号都是些什么设备可以看一下文件 <TT
CLASS="FILENAME"
>/usr/src/linux/Documentation/devices.txt</TT
>。</P
><P
>系统安装时,所有的这些设备文件都是由命令 <B
CLASS="COMMAND"
>mknod</B
> 建立的。去建立一个新的名叫'coffee',主设备号为<TT
CLASS="LITERAL"
>12</TT
>和从设备号为<TT
CLASS="LITERAL"
>2</TT
>的设备文件,只要简单的只能执行命令
<B
CLASS="COMMAND"
>mknod /dev/coffee c 12 2</B
>。你并不是必须将设备文件放在目录<TT
CLASS="FILENAME"
>/dev</TT
>中,这只是一个传统。Linus本人是这样做的,所以你最好也不例外。但是,当你测试一个模块时,在工作目录建立一个设备文件也不错。
只要保证完成后将它放在驱动程序找得到的地方。
</P
><P
>我还想声明在以上讨论中隐含的几点。当系统访问一个系统文件时,系统内核只使用主设备号来区别设备类型和决定使用何种内核模块。系统内核并不需要知道从设备号。内核模块驱动本身才关注从设备号,并用之来区别其操纵的不同设备。</P
><P
>另外,我这儿提到的硬件是比那种可以握在手里的PCI卡稍微抽象一点的东西。看一下下面的两个设备文件:</P
><TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
> % ls -l /dev/fd0 /dev/fd0u1680
brwxrwxrwx 1 root floppy 2, 0 Jul 5 2000 /dev/fd0
brw-rw---- 1 root floppy 2, 44 Jul 5 2000 /dev/fd0u1680
</PRE
></FONT
></TD
></TR
></TABLE
><P
>你现在立即明白这是快设备的设备文件并且它们是有相同的驱动内核模块来操纵(主设备号都为2)。你也许也意识到它们都是你的软盘驱动器,即使你实际上只有一个软盘驱动器。为什么是两个设备文件?因为它们其中的一个代表着你的<TT
CLASS="LITERAL"
>1.44</TT
>
<SPAN
CLASS="ACRONYM"
>MB容量的软驱,另一个代表着你的</SPAN
><TT
CLASS="LITERAL"
>1.68</TT
> <SPAN
CLASS="ACRONYM"
>MB容量的,被某些人称为“超级格式化”的软驱。这就是一个不同的从设备号代表着相同硬件设备的例子。请清楚的意识到我们提到的硬件有时可能是非常抽象的。</SPAN
></P
></DIV
></DIV
></DIV
><H3
CLASS="FOOTNOTES"
>注意</H3
><TABLE
BORDER="0"
CLASS="FOOTNOTES"
WIDTH="100%"
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN469"
HREF="x429.html#AEN469"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>这是一个去跟踪程序究竟在做什么的非常有价值的工具。</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN516"
HREF="x429.html#AEN516"
><SPAN
CLASS="footnote"
>[2]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>我是物理专业的,而不是主修计算机。</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN522"
HREF="x429.html#AEN522"
><SPAN
CLASS="footnote"
>[3]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>这不同于将所有的内核模块编译进内核,但意思确实是一样的。</P
></TD
></TR
></TABLE
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="c427.html"
ACCESSKEY="P"
>返回</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>返回首页</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="c569.html"
ACCESSKEY="N"
>继续</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>热身</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c427.html"
ACCESSKEY="U"
>返回本章开始</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>字符设备文件</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -