以文本方式查看主题

-  曙海教育集团论坛  (http://sun4.cn/bbs/index.asp)
--  Linux驱动开发  (http://sun4.cn/bbs/list.asp?boardid=33)
----  嵌入式Linux系统内核与设备驱动开发技术  (http://sun4.cn/bbs/dispbbs.asp?boardid=33&id=1703)

--  作者:wangxinxin
--  发布时间:2010-11-24 9:18:17
--  嵌入式Linux系统内核与设备驱动开发技术
序言

第一章 内核编译的基础

第一节内核简介

第二节内核版本

第三节编译原因

第四节准备工作

第二章 内核编译的流程

第一节编译开始 

第二节配置内核 {核心内容}

1.代码成熟等级

2..处理器类型和特色

3.对模块的支持

4.基本的选择

5.即插即用支持 

6.块设备支持

7.网络选项

8.电话支持

9.SCSI设备的支持 

10.I2O接口适配器

11.网络设备支持 

12.配置业余无线广播

13.红外支持

14.ISDN的文件系统 

15.旧型光驱类型(非IDE界面的光驱)

16.字符设备

17.USB支持

18.文件系统 

19.控制台驱动

20.声卡驱动

21.Kernel hacking 

第二节 内核版本 

由于Linux的源程序是完全公开的,任何人只要遵循GPL,就可以对内核加以修改并发布给他人使用。Linux的开发采用的是集市模型(bazaar,与cathedral--教堂模型--对应),为了确保这些无序的开发过程能够有序地进行,Linux采用了双树系统。一个树是稳定树(stable tree),另一个树是非稳定树(unstable tree)或者开发树(development tree)。一些新特性、实验性改进等都将首先在开发树中进行。如果在开发树中所做的改进也可以应用于稳定树,那么在开发树中经过测试以后,在稳定树中将进行相同的改进。一旦开发树经过了足够的发展,开发树就会成为新的稳定树。开发数就体现在源程序的版本号中;源程序版本号的形式为x.y.z:对于稳定树来说,y是偶数;对于开发树来说,y比相应的稳定树大一(因此,是奇数)。确定是以″ root ″的身份签入,然后cd 到 /usr/src 。uname -r 这个指令将会显示版本。内核版本的更新可以访问<http://www.kernel.org/>。

第三节 编译原因

Linux作为一个自由软件,在广大爱好者的支持下,内核版本不断更新。新的内核修订了旧内核的bug,并增加了许多新的特性。如果用户想要使用这些新特性,或想根据自己的系统度身定制一个更高效,更稳定的内核,就需要重新编译内核。通常,更新的内核会支持更多的硬件,具备更好的进程管理能力,运行速度更快、更稳
定,并且一般会修复老版本中发现的许多漏洞等,经常性地选择升级更新的系统内核是Linux使用者的必要操作内容。

为了正确的合理地设置内核编译配置选项,从而只编译系统需要的功能的代码,一般主要有下面四个考虑:

  ---自己定制编译的内核运行更快(具有更少的代码)
  ---系统将拥有更多的内存(内核部分将不会被交换到虚拟内存中)
  ---不需要的功能编译进入内核可能会增加被系统攻击者利用的漏洞
  ---将某种功能编译为模块方式会比编译到内核内的方式速度要慢一些

以上是针对成熟的Linux套件如Redhat Linux而言,我的目的是为建造嵌入式Linux操作系统做准备,也是必由之路。

第四节 准备工作

第一部分 新版本内核的获取和更新

Linux内核版本发布的官方网站是<http://www.kernel.org/>,国内各大ftp上一般都可以找到某些版本的内核。新版本的内核的发布有两种形式,一种是完整的内核版本,另外一种是patch文件,即补丁。完整的内核版本比较大,比如linux-2.4.0- test8.tar.bz2就有18M之多。完整内核版本一般是.tar.gz(.tgz)文件或者是.bz2文件,二者分别是使用gzip或者 bzip2进行压缩的文件,使用时需要解压缩。patch文件则比较小,一般只有几十K到几百K,极少的会超过1M。但是patch文件是针对于特定的版本的,需要找到自己对应的版本才能使用。编译内核需要root权限。把需要升级的内 拷贝到/usr/src/下(下文中以2.2.16的内核的 linux-2.2.16tar.gz为例),命令为

#cp linux-2.2.16tar.gz /usr/src

先查看当前/usr/src的内容,注意到有一个linux的符号链接,它指向一个类似于linux-2.2.14(对应于现在使用的内核版本号)的目录。首先删除这个链接:

#cd /usr/src
#rm -f linux 
现在解压下载的源程序文件。如果所下载的是.tar.gz(.tgz)文件,使用命令:

#tar -xzvf linux-2.2.16tar.gz

如果下载的是.bz2文件,例如linux-2.2.16tar.bz2,使用命令

#bzip2 -d linux-2.2.16tar.bz2
#tar -xvf linux-2.2.16tar

现在再来看一下/usr/src下的内容,发现现在有了一个名为linux的目录,里面就是需要升级到的版本的内核的源程序。还记得那个名为linux的链接么?之所以使用那个链接就是防止在升级内核的时候会不慎把原来版本内核的源程序给覆盖掉了。现在也需要同样处理:

#mv linux linux-2.2.16
#ln -s linux-2.2.16 linux

如果还下载了patch文件,比如patch-2.2.16,就可以进行patch操作(下面假设patch-2.2.16已经位于/usr/src目录下了,否则需要先把该文件拷贝到/usr/src下): 

#patch -p0 < patch-2.2.16

第二部分 准备主机板和相关硬件的说明手册

其实也不用太详细,只要知道您的硬件是属于哪一类型就行了。例如:有一张SCSI卡,那就要知道这张卡的名字,有一台cd-rom,就要知道这台光驱是哪一种牌子的,是否为标准的IDE/ATAPI界面,还是另有专属接口卡呢?或者,主机版是否有支持Triton芯片(通常586以上的电脑常有),这些信息能帮助我们,使得设定变得清楚且容易。因此,不管您有什么使用手册,准备好吧。即使现在不用,将来还是会用到的(设X-window system时要显示卡的手册)。

第三部分 检查声卡的IRQ设定和其种类

如果配有一张声卡,除了要知道卡的种类外(例如 Sound Blaster)还需要知道这张卡的IRQ地址。一般来说,卢卡的IRQ地址是5或7而IO地址则为220。DMA则l,不过,有时不同的声卡可能会有不同的设定。因为稍后的选项里,就会要填入这些数字。

第四部分 编译核心的硬件需求

在编译核心时,确定您的RAM最好在8MB以上, 否则可能会很慢而且问题会很多,记得查看swap有没有打开(用free指令)。此外,最好不要超频,不然很有可能会发生signal 11的错误,使得编到一半的核心停了下来,其实编译核心就好比编译程序一样,只是因为构成核心的程序太多了,因此我们能小心尽量小心。

第二章 内核编译的流程

概述编译的流程:

编译开始----- make mrproper;检查所需的连接
配置核心
编译核心
编辑/etc/lilo.conf
重新启动新核心
重新启动机器 
发现并修理故障(仔细看我的文章,应该没多少问题了)

第一节 编译开始

通常要运行的第一个命令是:

#cd /usr/src/linux 
#make mrproper 

该命令确保源代码目录下没有不正确的目标.o文件以及文件的互相依赖。如使用刚下载的完整的源程序包进行编译,本步可以省略。而如果多次使用了这些源程序编译内核,那么最好要先运行一下这个命令。

确保/usr/include/目录下的asm、linux和scsi等链接是指向要升级的内核源代码的。它们分别链向源代码目录下的真正的、该计算机体系结构(对于PC机来说,使用的体系结构是i386)所需要的真正的include子目录。如:asm指向/usr/src/linux/include /asm-i386等。若没有这些链接,就需要手工创建,按照下面的步骤进行:

# cd /usr/include
# rm -r asm linux scsi
# ln -s /usr/src/linux/include/asm-i386 asm
# ln -s /usr/src/linux/include/linux linux
# ln -s /usr/src/linux/include/scsi scsi

这是配置非常重要的一部分。删除掉/usr/include下的asm、linux和scsi链接后,再创建新的链接指向新内核源代码目录下的同名的目录。这些头文件目录包含着保证内核在系统上正确编译所需要的重要的头文件。也是上面又在/usr/src下"多余"地创建了个名为linux的链接的原因之一. 

一旦万事俱备,转到/usr/src/linux。现在你也许想停下细读一下文档文件,实际上如果你有些特别的硬件,或几种光驱驱动程需要自己动手设置,他们通常这样做,当引导时这些驱动程序将给出警告,这并不碍事他们照常工作少,阅读扩展名为.txt .h .c的文件。通常我发现他们具有共性且易于配置。如果你不想冒险,你没必要做。记住你照样可以解开tar文件(或再次安装.rpm文件)恢复前的文件。 

第二节 配置内核 核心内容

接下来的内核配置过程比较烦琐,但是配置的适当与否与日后Linux的运行直接相关,有必要了解一下选项的设置。

配置内核可以根据需要与爱好使用下面命令中的一个:

#make config (基于文本的最为传统的配置界面,不推荐使用)
#make menuconfig(基于文本选单的配置界面,字符终端下推荐使用,必须安装ncurses-dev和tk4-dev库) 
#make xconfig (基于图形窗口模式的配置界面,Xwindow下推荐使用)
#make oldconfig (如果只想在原来内核配置的基础上修改一些小地方,会省去不少麻烦)

如果不能使用Xwindow,那么就使用make menuconfig好了。界面虽然比上面一个差点,总比make config的要好多了。选择相应的配置时,有三种选择,它们分别代表的含义如下:

  Y--将该功能编译进内核
  N--不将该功能编译进内核
  M--将该功能编译成可以在需要时动态插入到内核中的模块 
在每一个选项前都有个括号, 但有的是中括号有的是尖括号,还有一种圆括号。 用空格键选择时可以发现,中括号里要么是空,要么是"*",而尖括号里可以是空,"*"和"M"。这表示前者对应的项要么不要,要么编译到内核里;后者则多一样选择,可以编译成模块。而圆括号的内容是要在所提供的几个选项中选择一项。在编译内核的过程中,最烦杂的事情就是这步配置工作了,不清楚到底该如何选取这些选项。实际上在配置时,大部分选项可以使用其缺省值,只有小部分需要根据用户不同的需要选择。选择的原则是将与内核其它部分关系较远且不经常使用的部分功能代码编译成为可加载模块,有利于减小内核的长度,减小内核消耗的内存,简化该功能相应的环境改变时对内核的影响;不需要的功能就不要选;与内核关心紧密而且经常使用的部分功能代码直接编译到内核中。下面对选项分别加以介绍。



1.Code maturity level options代码成熟等级

此处只有一项:prompt for development and/or incomplete code/drivers,如果要试验现在仍处于实验阶段的功能,比如khttpd、IPv6等,就必须把该项选择为Y了;否则可以把它选择为N。 在Linux的世界里,每天都有许多人为它发展支持的 driver和加强它的核心。但是有些driver还没进入稳定的阶段。但其作者很欢迎其他人去测试这些driver并提出一些bugs。这个问题是说,有一些drive还在做测试中,问您是否要选择这些drive或支持的程序码。

如果键入Y,往后将会出现一些还在测试中的东西给您做选择。(像Java的程序码和PCI bridge),台则就键入N。

2. Processor type and features处理器类型和特色

#Processor family (386, 486/Cx486, 586/K5/5x86/6x86, Pentium/K6/TSC,PPro /6x86MX) [PPro/6x86MX] ------选择处理器类型,缺省为Ppro/6x86MX。它会对每种CPU做最佳化,让它跑得快又好。一般来说,没有选择正确的CPU并不会有重大的影响(特别是选择386 ,这样编译出来的核心也许会比较小但它的速度可能就会变慢了)。所以,最好要知道您的CPU是哪一种。不过,如果您的gCC编译器是2.7.0版以前的。那么只能选择386或是486。

#High Memory Support------内核支持的最大内存数,缺省为1G。可以支持到4G、6.4G,一般可以不选. 

#Math emulation------这项询问是否需L1nux核心模拟数学浮点运算器。如果有486Dx、AMD以及Pentium机器的话,这个选项就不必选了,因为它们都有内建的浮点运算器。协处理器是在386时代的宠儿,现在早已不用了。不过,对于有内建浮点运算器的人来说,选了这个选项并不会因此让内建的浮点运算器失效。但它会增大核心约45KB。

#MTTR (memory type range register)support------选择该选项,系统将生成/proc/mtrr文件对 MTRR进行管理,供X server使用。同时用来启动pentinum pro和pentinum II 的特殊功能,如果你用的不是这类CPU就选 N,否则也仅仅是使内核变大而已。

#Symmetric multi-processing support------对称多处理支持。除非有多个CPU,否则就不用选了。

3. Loadable module support对模块的支持. 

首先,了解一点关于模块的知识。模块就像你特意插入核心中的某些东西,如果办公室有一个小网络并且有时想用一下(但并不经常),也许你想把网卡编译成一个模块。使用这个模块,机器必运行和存取/libs下的模块,意思是驱动程序(IDE,SCSI等但必须是NFS支持的网卡),文件系统(通常是ext2但也可以是nfs)和核心类型(最好是elf)必须编译在内核并且不能是模块,模块只有核心引导时才起作用,驱动程序(来网络)的存取,和文件系统安装。这些文件必须编译在核心内否则将能安装启动分区。如果安装启动分区和网络,你需要网络系统文件,和己经编译的网卡。为什么要使用模块? 模块化使核心变的更简捷,它减少核心释放大量的受保护的空间。模块的安装和卸载使用的空间是可重复分配利用的。如果你打开机器有90%以上的时间用到一个模块,编译它。运用这类模块是浪费内存的,原因是一旦你编译了模块它们同样将占用大量的内存,核心需要一些代码来挂上模块。记住,核心在保护空间运行,但模块并不是。这么说,并不经常使用我的设备,把它编译成只支持ext2,ide和elf。而一直使用的网卡,把其它的编译成模块:如 a.out, java, floppy, iso9960, msdos, minix, vfat,smb,nfs,smcultra(ethernetcard),serial,printer,sound,ppp, 等等。它们许多只是在这或那用上那么几分钟。严格的说,这样做会使核心增大许多而降低它的执行速度。这时我们就可以把这些可能会用的驱动程序编译成一个— 个的模块,在需要用的时候才用insmod这个指令加入核心,不用的时候也能rmmod把它从核心移除,或是用lsmod察看目前所载入的模块。这里面有三项:

#Enable loadable module support------除非准备把所有需要的内容都编译到内核里面,否则该项应该是必选的。

#Set version information on all module symbols------通常,我们更新核心版本之后,模块耍重新的编译。这个选项使您不必更新编译模块而能使用以前的模块。可以不选它。但如果您选y,则按照它的说明,您必须有genksyms这个程序(可用 whereis指令查看有无此程序)。

#Kernel module loader------让内核在启动时有自己装入必需模块的能力,建议选上。

注意:在开机就会 mount 上来的 partition 的 FS 、device driver 记得要 compiler 进 kernel,不能把它弄成 modules。请不要夸张到为了完全模组化而忘了把ext2fs和IDE dirver compiler 进 kernel 里。

#Support for hot-pluggabel devices ------热插拔设备支持。支持的不是太好,可不选。

#PCMCIA/CardBus support------PCMCIA/CardBus支持。有PCMCIA就必选了。

#PCI bridge optimization (experimental) ------在某些支持BIOS上,它能让存取速度加快,建议是选Y。

#Backward-compatible /proc/pci------设备兼容,自己看help。

#System V IPC 如果将来想编译dosemu(DOS模拟器),则这个选项一定要选,它是一个让各个程序(process)同步且能彼此交换数据的函数库和一些系统的调用,没它,很多的程序将会无法执行。

#BSD Process Accounting------ 

#Sysctl support------除非你的内存少的可怜,否则你应该启动这个功能,启用该选项后内核会大8K,但能让你直接改变内核的参数而不必重新开机。

#Kernel support for A.OUT binaries ------a.out的执行文件是比较古老的可执行码,用在比较早期的 UNIX系统上。Linux最初也是使用这种码来执行程序,一直到ELF格式的可执行码出来后,有愈来俞多的程序码随着ELF格式的优点而变成了ELF的可执码。将来势必完全取代a.out格式的可执行码。但目前由于沿有许多的程序还没有取代过来,所以只好选择Y,等将来有一天,全部的程序都变成了ELF 的天下时,那时再disable掉。