|
|
9月22日
从J-Link 4.09b开始这个问题就解决了,我也试过了,如果大家遇到这个问题可以尝试更新下J-Link软件。 10月9日
之前我预告过这篇文章,这段时间以来,我工作一直比较忙,而且在装修我的小破窝,生活的压力让我把业余的时间都贡献给奥山战场了,我的小牧师,杀人很慢,被杀倒是挺速度的,呵呵;想当年上学的时候,我也是副本RL,逃课带MC;现在工作了就只能沦为战场混荣誉的了……平时没有太多时间,职业不开UT跟混收麦子;周末开UT打各种麦子和各种国家队。国际惯例,二区风行者暗夜暗牧,多多和雯雯(Sigh,这个名字我GF取的,她叫雯雯和多多)。欢迎风行者的周末一同UT,我排队相当狠的,嘿嘿。
在开始前另外提一件事情,我之前说想找个便宜的PowerPC调试解决方案,现在其实我也算找到了——还是Macraigor的OCDRemote,用起来和OpenOCD差不多,具体用法和支持的器件请看Macraigor的官网 http://www.macraigor.com/。不过,“0f 84 f0 fc ff ff”->“0f 85 f0 fc ff ff”;我所提供的信息来自互联网,仅可以用于个人学习和研究,对于产生的后果,我不负任何责任;如果你喜欢这个软件,请联系Macraigor的销售,购买他们的调试硬件。但OCDRemote + Wiggler目前并不支持e300、e500内核,我要用的MPC8313还是调试不了……
首先明确一下,为什么我要抛开IAR、ADS、Keil这样的IDE选择GNU阵营的东西——这并不是因为GNU是自由软件,而是因为在一个CPU刚上手的时候,往往还是需要别人的代码来参考的,u-boot里面的样例很多,但是移植到IDE环境下开发却很困难。
ZylinCDT用起来很方便,只需要在Debug Configuration里面配置Commands选项卡,填入Initiate Commands和Run Commands;其他和Eclipse自己的Debug Configuration差不多。事实上,ZylinCDT就是用这些填入的内容取代了正常的GDB初始化命令,给出我的Initiate Commands给大家参考(Run Commands为空):
target remote 192.168.5.133:2331 # Disable watchdog monitor memU32 0xfffffd44 = 0x00008000
# PD6 - EBI0_NCS4, PD11 - EBI0_NCS2, PD15 - EBIO_CS3/NANDCS, PD16~PD31 - EBI0_D16~EBI0_D31 monitor memU32 0xfffff844 = 0xffff8840 monitor memU32 0xfffff864 = 0xffff8840 monitor memU32 0xfffff870 = 0xffff8840 monitor memU32 0xfffff804 = 0xffff8840
# Configure the EBI0 Slave Slot Cycle to 64 monitor memU32 0xffffec50 = 0x00000040
# Initialize the matrix, VDDIOMSEL = 1 -> Memories are 3.3V powered monitor memU32 0xffffed20 = 0x0001000a
# Configure SDRAM Configuration Register monitor memU32 0xffffe208 = 0x85227259 monitor sleep 10 # Perform Command - Precharge All monitor memU32 0xffffe200 = 0x00000002 monitor memU32 0x20000000 = 0x00000000 monitor sleep 20 # Perform Command - Refresh for 8 times monitor memU32 0xffffe200 = 0x00000004 monitor memU32 0x20000004 = 0x00000001 monitor memU32 0xffffe200 = 0x00000004 monitor memU32 0x20000008 = 0x00000002 monitor memU32 0xffffe200 = 0x00000004 monitor memU32 0x2000000c = 0x00000003 monitor memU32 0xffffe200 = 0x00000004 monitor memU32 0x20000010 = 0x00000004 monitor memU32 0xffffe200 = 0x00000004 monitor memU32 0x20000014 = 0x00000005 monitor memU32 0xffffe200 = 0x00000004 monitor memU32 0x20000018 = 0x00000006 monitor memU32 0xffffe200 = 0x00000004 monitor memU32 0x2000001c = 0x00000007 monitor memU32 0xffffe200 = 0x00000004 monitor memU32 0x20000020 = 0x00000008 # Perform Command - Load Mode Register monitor memU32 0xffffe200 = 0x00000003 monitor memU32 0x20000024 = 0xcafedede # Set Refresh Timer monitor memU32 0xffffe204 = 0x000002bc # Perform Command - Set Normal mode monitor memU32 0xffffe200 = 0x00000000 monitor memU32 0x20000000 = 0x00000000 file /home/lxz/share/u-boot-1.3.4/u-boot load
我调试的目标CPU是AT91SAM9263,通过以上的初始化命令,可以实现PLL、SDRAM的初始化,并将u-boot带码加载到内存中。J-Link的monitor命令可以看J-Link安装之后的文档J-Link GDB server user guide的3.4节Supported remote commands。
今天说的这些事情没有什么难度,用Eclipse + J-Link调试的关键就是要用ZylinCDT这样的插件,关于ZylinCDT的信息可以看它的官网 http://www.zylin.com/,解释的比我说的详细多了。Eclipse的教学文档网络上也多得很,Eclipse本身界面就很友好,不用什么教学,自己摸索一会儿也就会了。我就总结下:Eclipse可以自动创建Makefile,虽然使用的是GCC工具链,却有像ADS、Codewarrior这样IDE环境的便利;对于U-boot、Linux内核这样的有现成Makefile的程序,Eclipse能将它们导入,一样能调试。但是,和Source Insight强大的自动完成功能相比,Eclipse逊色太多了。我的开发解决方案是:Linux虚拟机下的SMB共享代码 + Windows下的Source Insight编辑 + Linux虚拟机下的arm-linux-gcc编译 + Windows下的J-Link GDB Server + Linux虚拟机下的Eclipse CDT & ZylinCDT;呵呵,好绕啊;但如果代码不复杂,就直接用Eclipse编辑也挺好。 7月23日
又是一个多月没有动这个Blog嘿嘿,我发现一个有趣的现象,我的Blog在每年的1月底到2月中旬,7月、8月是淡季,每天访问量基本都在100以下,其它时间都是旺季,尤其9月和3月,每天可以到200以上,最高甚至500。我想因该是因为学生们是EE小站访问的主力吧——9月和3月是开题的日子,这资料搜索做的,哈哈。现在是淡季,祝大家假期愉快,多陪陪父母。我现在就很后悔,大学的时候放假都在学校研究东西,就算回家,也背着全套的设备回去……现在工作了,根本没有时间回家看父母,唉。这段时间以来我一直在研究和调试相关的东西,最开始是想给MPC8313找一个便宜的调试方案,后来就找出来一大堆东西,但是就是没有合适8313用的。今天写的这个话题和学生们有很大关系,嘿嘿,怎样用最低的成本调试ARM,包括裸机调试和调试ARM Linux相关的东西。转载请注明来自EE小站,邮件 cosine@126.com。
先给大家介绍个大概情况,现在国内都有什么著名的ARM开发工具和解决方案,价格从高低排:
目前我知道的最牛X的调试工具,可以调试ARM、MIPS、PPC、ColdFire、XScale等多种处理器。无需更换硬件,只需要买不同的软件授权就可以调试不同的CPU。JTAG下载速度可以上兆,以太网接口。因为太贵了(BDI2000好像要人民币50000吧),我没怎么研究它到底配合什么软件来调试,不过GDB它是肯定支持的,它一直是我心目中的神话啊。
J-Link是IAR公司为ARM开发的调试工具,支持RDI协议的调试工具,如Keil、ADS、IAR等;支持GDB调试;什么SWD之类的用得很少,有没有都一样;但J-Link不支持ARM10以上的内核。JTAG下载的速度可以达到400~500K,正版价格大约5000人民币(全功能)吧,这么贵基本也不考虑了。
ARM公司的原创调试工具,支持全系列ARM芯片,现在多少钱我也不知道了,反正在2000~3000人民币这个级别。我这里指的是国内做得比较好的那些,比如Realview之类的。仅仅支持ADS、SDT之类的裸奔代码调试,JTAG下载速度130K左右。虽然这几年Multi-ICE是国内ARM调试绝对的霸主,但现在ARM公司已经停止对ADS的维护了,Multi-ICE会开始走向没落。
国内有很多Multi-ICE的盗版,功能和Multi-ICE原版一样,并口的、USB的都有,价钱几百块人民币,淘宝上到处都有。但是和J-Link盗版相比,不推荐购买。
最近这段时间,J-Link盗版渐渐开始多起来了,淘宝上也很多,功能和原版没有区别。价格大约在几百人民币左右,从性价比来看,推荐购买。我之后还会写一篇用J-Link调试ARM的文章,当你入门之后,绝对无法忍受今天介绍的这个低成本方案的JTAG下载速度,那时就买个J-Link来爽爽。
U-Link是Keil公司做的用于ARM和某些增强型8051调试的工具,由于Keil公司做U-Link的时候没有加密,导致现在盗版满天飞,只需要100多块钱就可以买到一个。现在Keil已经被ARM收购,U-Link也是ARM一家的了。U-Link正版在盗版的排挤下,根本没有什么买的必要;U-Link仅仅支持Keil,而且JTAG下载速度仅有20~30K。
Wiggler是世界上最泛滥的一种调试工具,它非常简单,只需要一片74HC244,一个9013,几个电阻就可以。本来Wiggler是Macraigor( http://www.macraigor.com/)制作的,可以支持Macraigor的OCDRemote这个GDB Server,可以支持ARM、PPC、ColdFire、MIPS、XScale等多种CPU。后来因为它结构太简单,被人破解后搞得全世界都是,于是Macraigor怒了,现在用OCDRemote必须是Macraigor原厂的Wiggler了……尽管如此,后人又在Wiggler的硬件基础上开发了很多的调试工具,例如H-Jtag;另外也有其他的调试工具增加了对Wiggler的支持,例如OpenOCD。Wiggler电缆的成本特别低,当然它的性能也和成本一样低;用H-Jtag下载速度大约20~30KB/s,用Linux虚拟机下的OpenOCD下载速度大约2KB/s。不过对于囊中羞涩的学生们来说,是一个非常不错的入门工具。本文就针对Wiggler进行介绍。
估计看这篇文章的人会有一些是从单片机起步,转到ARM上来的,我先梳理下各种CPU调试的知识。
这条路是学校教学比较传统的路子。条件好点的学校开单片机课的时候都有实验,用实验箱和仿真器做实验,那种仿真器就是一种最早的CPU/MCU仿真器,仿真器通过仿真头连接电路板,完全模拟CPU/MCU的功能;仿真器通过串口或者其他什么口连接计算机,计算机上有集编译器、调试器为一体的集成开发环境,可以监控和运行程序。这种仿真器的成本一般比较高,而且仿真不同的CPU/MCU需要不同的硬件,结构也很复杂,使用软件模拟的断点。解释下软件模拟的断点——就是用特殊的函数调用指令替换断点所在位置的指令,这些特殊的函数具有和仿真器的监控软件交互的功能。应该有很多的同学平时没有条件用上这么奢侈的设备,多半是用的是ISP,采用“点灯大法”——就是借助LED、串口之类的调试程序,每修改一次程序就重新下载一次,调试非常的艰苦。我刚开始玩单片机的时候AT的89S52还没有出来,我花一个月的生活费买了个烧写器,每次改程序都把芯片撬下来放到烧写器上,烧完再装回去继续点灯…… 走这条路,要明白的事情有:ARM的寄存器可不是51那寥寥可数的几个,是没有必要也不可能背下来的;ARM芯片一般都内置了JTAG调试逻辑,不需要CPU仿真器,需要的是一个JTAG协议转接器(虽然现在大家还叫这种东西为仿真器);集成开发环境在使用者看来和单片机的没有任何区别,这点请放心。
时代是不断进步的,AVR、C8051F具有JTAG口的单片机。JTAG(Joint Test Action Group)组织定了一个最初是用于测试生产出来的芯片是不是良品的测试接口和标准,在芯片的各个管脚上放上锁存器,然后串起来构成移位寄存器,可以监控芯片管脚的输入和输出;后来大家发现这东西用来搞芯片的在线调试不错,于是就出现了现在JTAG调试风行的局面。再说的明白些,也就是利用JTAG可以控制CPU内核,每个CPU都可以成为自己的“仿真器”,而不需要专用的设备。“人人都是食神。”——周星星语录。从理论上来说,世界上只需要一种仿真器,哦,确切的说应该叫做JTAG协议转换器,就可以调试所有的兼容JTAG标准的芯片;BDI2000这种超级贵的“仿真器”以及Wiggler这种什么都通吃的便宜货的存在是很合理的事情。 走这条路,应该已经明白了JTAG是什么,所以不用多说了。
正像Windows和Linux的对比,集成开发环境比GDB在嵌入式开发领域,拥有更多的用户,但这并不意味的GDB不好。GDB(GNU Project Debugger)是开源软件组织GNU开发和维护的一种调试工具,它能调试目前所有的能跑Linux的CPU,当然ARM也是其中一员。对于初学者来说,不建议使用GDB,还是先从集成开发环境入手,例如ADS、SDT、Keil、IAR之类的。其实从编译器的层面来讲,集成开发环境和GDB所用的编译器GCC没有什么区别,但集成开发环境里面提供了源文件组织与浏览、工程文件管理、调试等多种功能,用起来很友好。GCC+GDB光学习写相当于工程文件的Makefile就要花很多的时间。但是,一旦你的学习进了一步到了Linux的Loader和内核,集成开发环境就无能为力了。前面已经提到了,本文覆盖了从刚开始的裸奔代码到涉足操作系统的GCC+GDB调试环境的建立方法。本文关于GDB的部分应该是国内挺难找到的HOWTO,转载请注明来自EE小站。关于GDB,可以参考下我之前的这篇文章 http://xianzilu.spaces.live.com/blog/cns!4201FDC93932DDAF!268.entry。
在开始之前请先确认你的电脑有并口,如果是笔记本就算了,买个PCMIA转并口的卡的钱够买个盗版U-Link了;要是肯下血本买盗版J-Link,那就看我以后写的文章。
你需要的东西有:
● 带并口的电脑一台 ● 并口延长线一根 ● Wiggler一个 ● 随便什么ARM7或ARM9的开发板一个
如果没有并口延长线,可以去电脑城买一根。如果没有Wiggler,你可以选择DIY,下面这张图是Wiggler的一种版本:
如果不想DIY,上淘宝淘一个去。ARM开发板也可以在淘宝上淘淘,看你的经济能力了。
你需要的软件有:
● ADS (ARM Developer Suite) V1.2 ● H-Jtag
GDB使用GDB工具链,调试解决方案的结构是
GDB前端<--->GDB<--->GDB服务程序<--->JTAG协议转换器(仿真器)<--->目标CPU(ARM CPU) | 控制接口
GDB有一个很大的缺点——文本界面,使用非常不方便。但幸运的是,有很多热心的开发者为GDB写了一些图形“外壳”——GDB前端,大大方便了GDB的使用。因为我们做的是交叉开发(即在x86结构的电脑上开发ARM等非x86结构的CPU程序),所以GDB无法直接调试编译出来的程序,这就需要一个服务程序。这个服务程序可以是一个可以控制目标CPU的程序(可能运行于计算机上;也可能运行于某些仿真器上,例如如BDI2000就是这样),也可以是一个运行于目标CPU上的服务程序,由它来装载被调试的程序。但是后者一般需要目标CPU上已经运行起了Linux内核;调试Bootloader和Linux内核本身,需要前一种服务程序。GDB和GDB服务程序之间的连接方式可以是以太网或者串口,而且GDB服务程序一般还有别的控制接口,例如Telnet接口,可以实现对目标CPU的控制,如初始化和程序文件下载等。比较复杂哦,一会儿说到软件的时候就会用上这些知识。
你需要的东西和裸奔代码一样
你需要的软件有:
● 一个可以运行的Linux
● 本机GCC编译器
Open Suse自己带的就可以
● 交叉GCC编译器
● OpenOCD源码
● Insight源码
Insight是一个GDB的图形前端,我感觉它比DDD更适合嵌入式系统程序的调试。
● 随便什么程序的源码,例如U-Boot
U-Boot就不用介绍了,如果不知道可以Google下。
下面开始编译,先是OpenOCD,假设源代码已经解压缩到了/home/lxz/build-openocd,先设定权限
# cd /home/lxz/build-openocd
# chmod 755 ./bootstrap
# ./bootstrap
等一会儿,输入
# ./configure --prefix=/usr/local/arm/openocd --enable-parport
这里--prefix指定的是安装的路径,--enable-parport使能并口,然后
# make
# sudo make install
输入root密码,等一会儿,安装就完成了
然后是insight,假设源码已经解压缩到了/home/lxz/insight-6.8,然后
# cd /home/lxz/insight-6.8
# ./configure --prefix=/usr/local/arm/arm-linux-insight --target=arm-linux
这里--prefix指定的是安装的路径,--target指的是为ARM编译GDB,等一会儿,输入
# make
等一会儿,输入
# sudo make install
输入root密码,等一会儿,安装就完成了
然后编译一个U-Boot用于测试,假设源码已经解压缩到了/home/lxz/at91rm9200/u-boot-1.2.0,假设已经修改完了Makefile中的交叉编译器的选项,假设我为AT91RM9200DK开发板编译,然后
# cd /home/lxz/at91rm9200/u-boot-1.2.0
# make at91rm9200dk_config
# make
于是得到了/home/lxz/at91rm9200/u-boot-1.2.0/u-boot这个映像
# Daemon configuration telnet_port 23 gdb_port 2331 daemon_startup reset
# JTAG interface configuration interface parport jtag_speed 0 reset_config trst_and_srst jtag_device 4 0x1 0xf 0xe
# parport options parport_port 0x378 parport_cable wiggler
# Target configuration target arm920t little run_and_init 0 arm920t run_and_halt_time 0 1000 target_script 0 reset at91rm9200_init.script working_area 0 0x00200000 0x1000 backup
我还是提一下,上面这段配置信息中的target_script 0 reset at91rm9200_init.script这句就是指定第二个脚本的,而且让OpenOCD在当前目录下搜索这个脚本。也就是说,如果at91rm9200.cfg在/home/lxz/at91rm9200下,那么你在/home/lxz/at91rm9200下启动OpenOCD服务程序,OpenOCD就会在/home/lxz/at91rm9200下搜索at91rm9200_init.script这个脚本;如果在与at91rm9200.cfg所在路径不同的路径下启动OpenOCD服务程序,OpenOCD就无法找到at91rm9200_init.script,此时,target_script 0 reset at91rm9200_init.script这句就应该写成target_script 0 reset /home/lxz/at91rm9200/at91rm9200_init.script。
第二个脚本的作用是初始化ARM CPU,因为U-Boot往往是在SDRAM里运行的,其连接位置也都在SDRAM里。用GDB或GDB前端下载程序的时候,必须保证SDRAM是可用的。AT91RM9200这个CPU上电的时候如果从片内Boot ROM启动(不推荐从外部启动,因为如果没有启动程序,AT91RM9200将运行于慢时钟,这样JTAG仿真器可能工作不正常),需要进一步配置PLL,PIO,SDRMC之类的外设之后,SDRAM才可以使用。第二个脚本就是一系列寄存器读写和延时命令的集合,如何编写请看OpenOCD的手册 http://openfacts.berlios.de/index-en.phtml?title=OpenOCD_commands,给出我的at91rm9200_init.script。
mww 0xfffffc28 0x00000000 mww 0xfffffc2c 0x00000000 mww 0xfffffc20 0x0000ff01 sleep 20 mww 0xfffffc28 0x20263e04 sleep 20 mww 0xfffffc2c 0x10483e0e sleep 20 mww 0xfffffc30 0x00000000 sleep 20 mww 0xfffffc30 0x00000202 sleep 20 mww 0xfffff870 0xffff0000 mww 0xfffff804 0xffff0000 mww 0xffffff60 0x00000002 mww 0xffffff64 0x00000000 mww 0xffffff98 0x2188c159 mww 0xffffff90 0x00000002 mww 0x20000000 0x00000000 mww 0xffffff90 0x00000004 mww 0x20000000 0x00000000 mww 0x20000000 0x00000000 mww 0x20000000 0x00000000 mww 0x20000000 0x00000000 mww 0x20000000 0x00000000 mww 0x20000000 0x00000000 mww 0x20000000 0x00000000 mww 0x20000000 0x00000000 mww 0xffffff90 0x00000003 mww 0x20000200 0x00000000 mww 0xffffff94 0x000002e0 mww 0x20000000 0x00000000 mww 0xffffff90 0x00000000 mww 0x20000000 0x00000000 arm7_9 sw_bkpts enable
这个脚本写起来很复杂,建议从一些样例代码上把寄存器的数值扒过来。另外,有些CPU,例如S3C2410,它上电的时候,SDRAM是默认可以用的,就不需要这个脚本了。还有一个值得注意的是,由于我们用的是Wiggler这种简单的JTAG协议转换器,初始化脚本里必须加上arm7_9 sw_bkpts enable这句。现在终于可以开始调试了,假设把OpenOCD安装在了/usr/local/arm/openocd,把Insight安装在了/usr/local/arm/arm-linux-insight,两个初始化脚本都放在了/home/lxz/at91rm9200;你已经正确连接了Wiggler,开发板已经上电。接下来还是用命令来说明
# cd /home/lxz/at91rm9200
# sudo /usr/local/arm/openocd/bin/openocd -f at91rm9200.cfg
root's password: Open On-Chip Debugger 1.0 (2008-07-21-20:15) svn: $URL: http://svn.berlios.de/svnroot/repos/openocd/trunk/src/openocd.c $ Info: jtag.c:1329 jtag_examine_chain(): JTAG device found: 0x05b0203f (Manufacturer: 0x01f, Part: 0x5b02, Version: 0x0) Info: target.c:240 target_init_handler(): executing reset script 'at91rm9200_init.script' Info: options.c:50 configuration_output_handler(): software breakpoints enabled
这就说明OpenOCD已经开始工作了。然后启动Insight
# cd /home/lxz/at91rm9200/u-boot-1.2.0/
# /usr/local/arm/arm-linux-insight/bin/arm-linux-insight
出现下面的窗口
然后选择菜单File>Target Settings...,在出现的窗口中进行如下设置,然后点OK。
选择菜单File>Open,打开/home/lxz/at91rm9200/u-boot-1.2.0/u-boot这个映像;然后选择菜单Run>Download,将U-Boot程序下载到目标CPU。然后在程序运行的必经之路设定一个断点,如下图所示。
选择菜单Control>Continure,程序就会从头开始执行,并停在断点处了。Insight还有很多不错的功能,并且很容易上手,大家研究下就好。补充一点,如果你对你的初始化脚本是否起作用没有信心,可以在启动Insight之后只选择菜单Run>Connect to target,然后选择菜单View>Memory查看各个寄存器和内存。最后给出一张我用Insight调试U-Boot的截图。
在使用的过程中就会发现,用Wiggler下载的速度实在不怎么样,U-Boot的可执行映像至多只有200KB,所以还是可以忍受的。
用同样的方法也可以调试其他Boot Loader,甚至是Linux内核;但是Linux内核的可执行映像一般有2MB之大,用Wiggler调试也是不现实的。我之前已经做了广告了,内核的调试要用J-Link来搞,敬请期待EE小站的后续文章。
我对ARM CPU的在线Flash Download这件事情不是很感冒,所以H-JTAG和OpenOCD的这部分功能EE小站是不会涉及了,请见谅。今天就到这里。
3月15日 大约半年前,我写了篇文章,介绍了如何在ARM Linux上使用OpenGL|ES软件包。但是运行的速度实在是太慢了。在ARM上流畅运行OpenGL一直是令我耿耿于怀的一个怨念。最近一段时间研究了下OpenGL,在别人代码的基础上(Mesa,TinyGL),写出了一个可以裸机运行的超精简OpenGL软件包,总共代码只有1600行。运行在具有2D图形加速功能的SOC处理器上,可以获得很不错的效果。但是这不是我最终的目的,我想要把这个软件包中的大多数功能改写成VHDL,实现硬件3D加速。当然,这个软件包的功能是为我从事的行业专门设计的,用于消费电子基本是不可能的。贴上一张图片,给大家看看。
这个东西对我来说太有用了,更多的信息不能公开,抱歉了。如果你想进行这方面的研究,我可以给点资料提示,第一就是上面图片里这本书,俗称“OpenGL红宝书”;第二是随便什么讲计算机图形方面的书,只要涉及到画线、多边形填充算法,2维和3维投影变换,光源计算等,就可以。 2月23日 我相信这篇文章同样是国内很难搜到的一个HOWTO(呵呵,截至到我写出来之前),我的最初目的是在ARM上使用PHP,尝试了Busybox的httpd,以及boa都没有办法很方便的和PHP接口,因此我狠下心来,编译了Apache。在ARM上使用PHP,好处仅仅是脚本比cgi好写一些,付出的代价是速度和蜗牛一样慢,不要指望很多人同时访问可以响应得过来。
另外说件事,BLOG上的文章多了,经常发现有人转载,但是有的人却不注出处……难道要我吧我的名字和邮件地址写到文章的每一个部分吗?也许国人就是这样缺乏某种精神,在我看到的转载我文章的BLOG中,基本都是网上各种ARM Linux文章的集合,不可否认他们搜集的很好,但是看了这么多文章,连一点心得体会都没有么,写点原创的东西就这么难么?不管怎样,我还是坚持EE小站的风格——原创性。下面开始正题,本文分为三大部分,apache、php和配置。
下载apache 1.3.39(1.3.41有些bug,没有办法交叉编译) 下载地址http://apache.mirror.phpchina.com/httpd/apache_1.3.39.tar.bz2
交叉编译apache总体上需要两个步骤: 1.编译本机代码 2.利用本机代码进行交叉编译
这是因为编译apache时,需要使用编译生成的工具制作后续编译使用的头文件,交叉编译的工具当然没有办法在PC上运行,因此,需要借用本机编译生成的工具。假设为本机编译的apache代码已经解压缩到/home/lxz/apache-1.3.39-i586,为ARM编译的apache代码已经解压缩到/home/lxz/apache-1.3.39,交叉编译器arm-linux-gcc已设缺省路径,具体步骤还是用命令来说明:
# cd /home/lxz/apache-1.3.39-i586 # ./configure
因为仅仅是借用下本机代码,所以不用设置配置参数,然后编译
# make
等编译完成后,就可以配置交叉编译的apache了。apache的安装位置为/usr/local/apache
# cd /home/lxz/apache-1.3.39 # CC=arm-linux-gcc ./configure --prefix=/usr/local/apache
会出来这样的提示,因为交叉编译的生成的testfunc这个工具不能在PC上执行,但可以不理会它
./helpers/TestCompile: line 294: /home/lxz/apache-1.3.39/src/helpers/testfunc: cannot execute binary file
打开/home/lxz/apache-1.3.39/src/main/Makefile这个文件,找到这两段代码
uri_delims.h: gen_uri_delims ./gen_uri_delims >uri_delims.h
test_char.h: gen_test_char ./gen_test_char >test_char.h
修改为
uri_delims.h: gen_uri_delims /home/lxz/apache-1.3.39-i586/src/main/gen_uri_delims >uri_delims.h
test_char.h: gen_test_char /home/lxz/apache-1.3.39-i586/src/main/gen_test_char >test_char.h
这里借用了刚才编译生成的本机代码里的工具,然后
# make
这就编译好了,下面是安装。由于配置apache的时候“prefix”参数指定的安装位置是/usr/local/apache,在PC上,访问/usr/local是需要有root权限的,需要切换到root用户来进行安装。不建议将apache安装到一个随意的目录然后拷贝,因为这样会造成apache中的脚本调用位置的错误。当然,如果想要将apache安装到一个PC和ARM Linux都能访问的固定位置,如/home/lxz/apache也可以。
如果你不明白上面这段话在说什么,那么请按照下面的步骤进行操作。请确认你的PC Linux上的/usr/local/apache这个目录不存在PC上使用的apache,否则下面的步骤会使你PC Linux上的apache不可用。
# su root
输入密码
# cd /home/lxz/apache-1.3.39/ # make install # exit
别忘了用exit退出root用户模式,这样,apache的文件就被安装到PC上的/usr/local/apache了。接下来所要做的是将apache拷贝到ARM Linux根文件系统,假设ARM Linux根文件系统在PC上的位置为/home/lxz/root,其中已经有/usr/local这个目录
# cp -r /usr/local/apache /home/lxz/root/usr/local
如果是一路看着我的BLOG建立起根文件系统的,接下来还必须建立nobody用户和nogroup组,因为apache拒绝使用root用户运行。具体来说就是在ARM Linux根文件系统上建立/etc/passwd和/etc/group两个文件,怎么写这两个文件,可以google下。它们的内容可以如下:
/etc/passwd
root::0:0:root:/:/bin/ash nobody::65534:65533:nobody:/:/bin/ash
/etc/group
nobody::65533: nogroup::65534:nobody root::0: users::100:
当然,如果你的ARM Linux根文件系统中有这两个文件,那么你需要检查一下是不是有nobody用户和nogroup组。接下来,可以制作文件系统映像并测试apache是否可以正常工作了,还是用命令来说明。
# mkfs.cramfs /home/lxz/root /home/lxz/root.img
我一直用cramfs,SUSE 10.2自己就带了mkfs.cramfs这个工具。烧写或者加载文件系统映像的步骤我就不说了,需要注意的是如果你使用了不可写的文件系统,如cramfs,需要把apache的日志路径挂载为临时文件目录,下面这几条命令在ARM Linux上执行。
# mount -t tmpfs tmpfs /usr/local/apache/log
然后就可以启动apache了
# cd /usr/local/apache/bin # ./apachectl start
假设ARM板的ip地址是192.168.5.118,在浏览器里输入http://192.168.5.118:8080访问ARM板(不修改默认配置,服务端口是8080)。apache的配置一会儿编译了php再说。
首先下载php-4.4.8,下载地址:http://cn2.php.net/get/php-4.4.8.tar.bz2/from/this/mirror
交叉编译php同样需要两个步骤: 1.编译本机代码 2.利用本机代码进行交叉编译
原因我就不重复了,假设为本机编译的php代码已经解压缩到/home/lxz/php-4.4.8-i586,为ARM编译的php代码已经解压缩到/home/lxz/php-4.4.8,交叉编译器arm-linux-gcc已设缺省路径,具体步骤还是用命令来说明:
# cd /home/lxz/php-4.4.8-i586 # ./configure # make
在编译的同时,可以打开/home/lxz/php-4.4.8/configure这个文件,搜索“can not run test program while cross compiling”,会搜索到很多个这样的结果:
{ echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
把它们都改为
{ echo "configure: error: can not run test program while cross compiling" 1>&2; }
这样做的目的是直接无视交叉编译测试程序错误。另外,我使用的是arm-linux-gcc 3.4.1版,和代码不太兼容。找到/home/lxz/php-4.4.8/Zend/zend_strtod.c的第238行
#if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + \ defined(IBM) != 1 Exactly one of IEEE_LITTLE_ENDIAN IEEE_BIG_ENDIAN, VAX, or IBM should be defined. #endif
把这段改为
#if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + \ defined(IBM) != 1 //Exactly one of IEEE_LITTLE_ENDIAN IEEE_BIG_ENDIAN, VAX, or //IBM should be defined. #endif
在本机php编译完后,输入如下命令
# cd /home/lxz/php-4.4.8 # CC=arm-linux-gcc ./configure --prefix=/usr/local/php --host=i586-suse-linux --target=arm-linux
别以为可以编译了,还有东西要修改,真汗啊……打开/home/lxz/php-4.4.8/Makefile,找到这段
install-pear-packages: $(top_builddir)/sapi/cli/php @$(top_builddir)/sapi/cli/php $(PEAR_INSTALL_FLAGS) /home/lxz/php-4.4.8/pear/install-pear.php -d "$(peardir)" -b "$(bindir)" /home/lxz/php-4.4.8/pear/packages/*.tar
用上我们刚才编译的本机php里的文件,把它改成
install-pear-packages: /home/lxz/php-4.4.8-i586/sapi/cli/php @/home/lxz/php-4.4.8-i586/sapi/cli/php $(PEAR_INSTALL_FLAGS) /home/lxz/php-4.4.8/pear/install-pear.php -d "$(peardir)" -b "$(bindir)" /home/lxz/php-4.4.8/pear/packages/*.tar
终于可以编译了
# make
随后和apache一样,需要切换用户,把php的文件安装到/usr/local/php
# su
输入密码
# cd /home/lxz/php-4.4.8 # make install # exit
这样,php就编译完成了。
接下来就需要修改配置文件,让apache和php能够链接起来工作。这个配置过程和Windows下使用apache+php的过程类似,因为我不是把apache和php一起编译的,只是让apache认识“.php”这个扩展名,然后调用php。为了方便,直接给出apache的配置文件,配置文件的位置在ARM Linux文件系统的/usr/local/apache/conf/httpd.conf,其中红色字是在默认配置文件基础上修改或添加的内容。
ServerType standalone ServerRoot "/usr/local/apache" PidFile /usr/local/apache/logs/httpd.pid ScoreBoardFile /usr/local/apache/logs/httpd.scoreboard Timeout 300 KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 15 MinSpareServers 5 MaxSpareServers 10 StartServers 5 MaxClients 150 MaxRequestsPerChild 0 Port 80User nobody Group nobody ServerAdmin cosine@126.comDocumentRoot "/home/webroot"
<Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory "/home/webroot"> Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny Allow from all </Directory><IfModule mod_userdir.c> UserDir public_html </IfModule> <IfModule mod_dir.c> DirectoryIndex index.html DirectoryIndex index.php DirectoryIndex index.php3 DirectoryIndex index.phtml</IfModule> AccessFileName .htaccess <Files ~ "^\.ht"> Order allow,deny Deny from all Satisfy All </Files> UseCanonicalName On <IfModule mod_mime.c> TypesConfig /usr/local/apache/conf/mime.types </IfModule> DefaultType text/plain <IfModule mod_mime_magic.c> MIMEMagicFile /usr/local/apache/conf/magic </IfModule> HostnameLookups Off ErrorLog /usr/local/apache/logs/error_log LogLevel warn LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common LogFormat "%{Referer}i -> %U" referer LogFormat "%{User-agent}i" agent CustomLog /usr/local/apache/logs/access_log common ServerSignature On <IfModule mod_alias.c> Alias /icons/ "/usr/local/apache/icons/" <Directory "/usr/local/apache/icons"> Options Indexes MultiViews AllowOverride None Order allow,deny Allow from all </Directory> Alias /manual/ "/usr/local/apache/htdocs/manual/" <Directory "/usr/local/apache/htdocs/manual"> Options Indexes FollowSymlinks MultiViews AllowOverride None Order allow,deny Allow from all </Directory> ScriptAlias /cgi-bin/ "/usr/local/apache/cgi-bin/" ScriptAlias /php4/ "/usr/local/php/bin/"
# 注意 "/usr/local/php/bin/" 中最后一个"/"不可少 <Directory "/usr/local/apache/cgi-bin"> AllowOverride None Options None Order allow,deny Allow from all </Directory> </IfModule> <IfModule mod_autoindex.c> IndexOptions FancyIndexing AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip AddIconByType (TXT,/icons/text.gif) text/* AddIconByType (IMG,/icons/image2.gif) image/* AddIconByType (SND,/icons/sound2.gif) audio/* AddIconByType (VID,/icons/movie.gif) video/* AddIcon /icons/binary.gif .bin .exe AddIcon /icons/binhex.gif .hqx AddIcon /icons/tar.gif .tar AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip AddIcon /icons/a.gif .ps .ai .eps AddIcon /icons/layout.gif .html .shtml .htm .pdf AddIcon /icons/text.gif .txt AddIcon /icons/c.gif .c AddIcon /icons/p.gif .pl .py AddIcon /icons/f.gif .for AddIcon /icons/dvi.gif .dvi AddIcon /icons/uuencoded.gif .uu AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl AddIcon /icons/tex.gif .tex AddIcon /icons/bomb.gif core AddIcon /icons/back.gif .. AddIcon /icons/hand.right.gif README AddIcon /icons/folder.gif ^^DIRECTORY^^ AddIcon /icons/blank.gif ^^BLANKICON^^ DefaultIcon /icons/unknown.gif ReadmeName README.html HeaderName HEADER.html IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t </IfModule> <IfModule mod_mime.c> AddLanguage da .dk AddLanguage nl .nl AddLanguage en .en AddLanguage et .ee AddLanguage fr .fr AddLanguage de .de AddLanguage el .el AddLanguage he .he AddCharset ISO-8859-8 .iso8859-8 AddLanguage it .it AddLanguage ja .ja AddCharset ISO-2022-JP .jis AddLanguage kr .kr AddCharset ISO-2022-KR .iso-kr AddLanguage nn .nn AddLanguage no .no AddLanguage pl .po AddCharset ISO-8859-2 .iso-pl AddLanguage pt .pt AddLanguage pt-br .pt-br AddLanguage ltz .lu AddLanguage ca .ca AddLanguage es .es AddLanguage sv .sv AddLanguage cs .cz .cs AddLanguage ru .ru AddLanguage zh-TW .zh-tw AddCharset Big5 .Big5 .big5 AddCharset WINDOWS-1251 .cp-1251 AddCharset CP866 .cp866 AddCharset ISO-8859-5 .iso-ru AddCharset KOI8-R .koi8-r AddCharset UCS-2 .ucs2 AddCharset UCS-4 .ucs4 AddCharset UTF-8 .utf8 <IfModule mod_negotiation.c> LanguagePriority en da nl et fr de el it ja kr no pl pt pt-br ru ltz ca es sv tw </IfModule> AddType application/x-tar .tgz AddType application/x-httpd-php .php3 AddType application/x-httpd-php .php AddType application/x-httpd-php .phtml AddEncoding x-compress .Z AddEncoding x-gzip .gz .tgz </IfModule> Action application/x-httpd-php "/php4/php" <IfModule mod_setenvif.c> BrowserMatch "Mozilla/2" nokeepalive BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0 BrowserMatch "RealPlayer 4\.0" force-response-1.0 BrowserMatch "Java/1\.0" force-response-1.0 BrowserMatch "JDK/1\.0" force-response-1.0 </IfModule>
php也有配置文件,但是修改起来比较简单,只需要把/home/lxz/php-4.4.8/php.ini-dist复制到ARM Linux文件系统的/usr/local/php/lib,并改名为php.ini,找到
register_globals = Off
修改为
register_globals = On
保存就可以了。
12月21日 关于根文件系统的制作,网络上有很多文章,大多数都只讲到建几个目录,然后用Busybox做个Shell,有很多关键的东西没有说。经过很长时间的摸爬滚打,我终于能够白手起家建立一个根文件系统了。其实我也不懂得原理,只是告诉大家我的作法,其中也不免有错误,欢迎大家指正。
2009年2月21日追加:这篇文章已经被无数的人转载,在Google和百度上搜文章标题,出来的已经不是EE小站的文章了。今天修改了其中的两个连接,估计已经转载的就没法修改了,所以请转载时注明来自 EE小站,谢谢。
首先介绍根文件系统的组成:目录、Shell、库、脚本,一个个来。
根文件系统要包含这些必须有的目录:/dev、/bin、/usr、/sbin、/lib、/etc、/proc、/sys
/dev是devfs(设备文件系统)或者udev的挂在点所在。在使用devfs的内核里如果没有/dev,根本见不到Shell启动的信息,因为内核找不到/dev/console;在使用udev的系统里,也事先需要在/dev下建立console和null这两个节点。关于devfs和udev的区别,网上很多文章说。当然如果你的内核已经不支持devfs了(2.6.12以后),可以使用纯纯的静态节点。也就是用mknod人工生成。
/bin、/usr/bin、/usr/sbin、/sbin是编译Busybox这个Shell时候就有的,用于存放二进制可执行文件,就不多解释了。
/lib用于存放动态链接库。网上很多文章都说静态编译Busybox,可以省去建库的麻烦过程。这样做只能让Busybox启动,我们自己写的,或者是编译的软件包还是需要动态库的。除非全部静态编译,你可以试试,一个Hello world就要几百k。关于库的内容后面仔细说。
/etc是用来存放初始化脚本和其他配置文件的。关于初始化脚本的内容后面仔细说。
/proc是用来挂载存放系统信息虚拟文件系统——“proc文件系统”,“proc文件系统”在内核里面可以选。如果没有“proc文件系统”,很多Shell自己的命令就没有办法运行,比如ifconfig。“proc文件系统”不像devfs可以自动挂载,它需要使用初始化脚本挂载。另外,udev也需要“proc文件系统”的支持。
/sys用于挂载“sysfs文件系统”,“sysfs文件系统”在内核里面可以选。目前我认为它就是给udev提供支持的,呵呵。“sysfs文件系统”也需要使用初始化脚本挂载。
另外还可以有/tmp、/mnt、/swp、/var这样的不是嵌入式系统必须的目录,在说完Shell的制作之后,我再谈建立目录的事情。
Shell很简单,就是Busybox,上网下载一个来: http://www.busybox.net/downloads/。说Busybox和arm-linux-gcc有兼容性问题,不过我觉得那是比较低版本的时代问题了,我用Busybox 1.8.2和arm-linux-gcc 3.4.1/3.3.2都可以。解压缩以后找到Makefile里面的ARCH和CROSS_COMPILE,改成: ARCH ?= arm CROSS_COMPILE ?= /usr/local/arm/3.4.1/bin/arm-linux- 当然CROSS_COMPILE由你自己的编译器位置决定,然后 # make menuconfig # make # make install 注意配置的时候把一些uCLinux Only的东西去掉,不然会错;配置的时候还可以修改安装位置,默认是在Busybox下的“_install”。
之后就可以在Busybox生成的Shell基础上建立根文件系统了,我就用命令来说吧,Busybox在/home/lxz/busybox,根文件系统在/home/lxz/rootfs
# mkdir /home/lxz/rootfs # cd /home/lxz/busybox/_install # cp -r ./ /home/lxz/rootfs
# cd /home/lxz/rootfs # mkdir dev # mkdir etc # mkdir lib # mkdir proc # mkdir sys # mkdir tmp
如果不用devfs,下面的命令是必须的。必须以root用户执行(用su命令可以切换为root,切换后用exit命令可以返回普通用户):
# cd /home/lxz/rootfs/dev # mknod -m 660 console c 5 1 # mknod -m 660 null c 1 3
如果不使用devfs没有这两个静态节点,console的提示根本就看不到,出现的现象可能是内核提示Free init memory: XXK之后,Warning: Unable to find a initial console之类的,具体的单词记得不是很准确。我没有试过使用udev的时候没有这两个静态节点的情况,反正放了也不影响把/dev挂载为tmpfs。
如果使用udev,还需要把udevd、udevstart、udevadmin这三个文件放到/sbin里面(我使用udev-117,网上介绍较多的udev-100有9个文件要放)。
库可是一件非常麻烦的事请。我建议初学者拷贝买的开发板里面带的文件系统的库,如果开发板的文件系统是映像,只需要把映像挂载在某个目录下就可以访问,假设映像叫做rootfs.cramfs,可以这样
# mkdir /home/lxz/evb_rootfs (切换为root用户) # mount -o loop rootfs.cramfs /home/lxz/evb_rootfs (可以切换为普通用户) # cd /home/lxz/evb_rootfs/lib # cp -r ./ /home/lxz/rootfs/lib
一般开发板里都会带有很多库,但是总体积却比较大。可以删掉一些不用的库来减小体积,但是,呵呵,我也不知道那些库具体含有什么函数,什么情况删什么;也许以后我会把这部分补上。如果觉得库体积太大,也可以自己编译glibc或者uclibc,但是这是非常繁琐的事请——目前我认为库应该和编译器arm-linux-gcc一起制作。有个傻瓜式的方案是使用cross-tool,下载地址: http://www.kegel.com/crosstool/。虽然cross-tool是用来制作交叉编译器的,但是其过程中生成的glibc却可以作为副产品为我们所用。cross-tool的使用可以看我之前的这篇文章 http://xianzilu.spaces.live.com/blog/cns!4201FDC93932DDAF!274.entry。在成功制作了交叉编译器之后,就可以从cross-tool的目录里把glibc取出来,假设cross-tool的路径是/home/lxz/cross-tool,编译出的编译器叫做arm-linux-gnu-gcc,gcc版本3.4.5,glibc版本2.3.6,想要把glibc库拷贝到/home/lxz/glibc,下面的操作还是用命令来说明。
# cd /home/lxz/cross-tool/build/arm-linux-gnu-gcc/gcc-3.4.5-glibc-2.3.6/build-glibc
# ../glibc-2.3.6/configure --prefix=/home/lxz/glibc
# make install
等候安装结束
# cd /home/lxz/glibc
# cp -r lib /home/lxz/rootfs
这样就把glibc的大部队拷贝好了,但是这样还缺两个库,我们继续
# cd /home/lxz/cross-tool/build/arm-linux-gnu-gcc/gcc-3.4.5-glibc-2.3.6/build-gcc/gcc
# cp libgcc_s.so* /home/lxz/rootfs/lib
# cd /home/lxz/libtermcap
# rpm2cpio libtermcap-2.0.8-35.src.rpm | cpio -ivd # tar xvjf termcap-2.0.8.tar.bz2 接下来要打13个补丁,很汗啊,请一定按照下面的顺序来打补丁
# patch -p0 -i termcap-2.0.8-shared.patch # patch -p0 -i termcap-2.0.8-setuid.patch # patch -p0 -i termcap-2.0.8-instnoroot.patch # patch -p0 -i termcap-2.0.8-compat21.patch # patch -p0 -i termcap-2.0.8-xref.patch # patch -p0 -i termcap-2.0.8-fix-tc.patch # patch -p0 -i termcap-2.0.8-ignore-p.patch # patch -p0 -i termcap-buffer.patch # patch -p0 -i termcap-2.0.8-bufsize.patch # patch -p0 -i termcap-2.0.8-colon.patch # patch -p0 -i libtermcap-aaargh.patch # patch -p0 -i termcap-2.0.8-glibc22.patch # patch -p0 -i libtermcap-2.0.8-ia64.patch
然后到/home/lxz/libtermcap/termcap-2.0.8里,找到Makefile,修改其中的CC和AR,
CC = /usr/local/arm/3.4.1/bin/arm-linux-gcc
AR = /usr/local/arm/3.4.1/bin/arm-linux-ar
# cd /home/lxz/libtermcap/termcap-2.0.8
# make
# ln -s libtermcap.so.2.0.8 libtermcap.so.2
# cp libtermcap.so* /home/lxz/rootfs/lib
这样,Shell启动所需要的基本库就都备齐了。但是,这些库里面还含有调试信息,体积稍大,可以把这些信息去掉(当然不去掉也没有什么影响)。
# cd /home/lxz/rootfs/lib
# arm-linux-strip *.so*
至此,库就制作好了。
有了以上的东西,Shell还是不能正常工作。可能会是内核提示Free init memory: XXK之后就什么输出也没有了,这时候向终端敲入文字,可以显示;就是没有终端提示符,不理会输入的命令。这是因为初始化脚本没有启动Shell。下面介绍这些脚本。
首先是/etc/inittab。内核启动、根文件系统挂载之后所必须的一个文件,其中列举了Shell和整个系统初始化、关闭所需的命令。如果你想让Shell出现,那么只需要加入这么一行“::askfirst:/bin/ash”。当然如果在编译Busybox的时候选择的shell不是“ash”,而是hush、lash、msh之类,那就改成相应的东西。除了启动Shell,inittab还干了很多事情,我就用我的inittab来说明了。注意,在编译Busybox的时候要选上touch、syslogd、klogd等命令。
# Startup the system null::sysinit:/bin/mount -o remount,rw / null::sysinit:/bin/mount -t proc proc /proc null::sysinit:/bin/mount -a null::sysinit:/bin/hostname -F /etc/hostname
# Now run any rc scripts ::sysinit:/etc/init.d/rcS
# Now invoke shell ::askfirst:/bin/ash
# Logging junk null::sysinit:/bin/touch /var/log/messages null::respawn:/sbin/syslogd -n -m 0 null::respawn:/sbin/klogd -n
# Stuff to do for the 3-finger salute ::ctrlaltdel:/sbin/reboot
# Stuff to do before rebooting null::shutdown:/usr/bin/killall klogd null::shutdown:/usr/bin/killall syslogd null::shutdown:/bin/umount -a -r null::shutdown:/sbin/swapoff -a
好,把上面这些储存为inittab,启动系统。应该出现两个提示,没有/etc/fstab和/etc/init.d/rcS。目前我的理解/etc/fstab是用来执行mount -a命令的,里面是文件系统的挂载表。还是用我的fstab来说明。
# <file system> <mount pt> <type> <options> <dump> <pass> /dev/root / ext2 rw,noauto 0 1 proc /proc proc defaults 0 0 devpts /dev/pts devpts defaults,gid=5,mode=620 0 0 tmpfs /tmp tmpfs defaults 0 0 sysfs /sys sysfs defaults 0 0
还有/etc/init.d/rcS,这在PC上是用来执行/etc/init.d下所有初始化脚本的一个脚本,呵呵,请原谅我不懂得怎么写这种脚本,对于嵌入式系统,根本不需要这么复杂,直接写在/etc/init.d/rcS里面了。还是用我的/etc/init.d/rcS来说明,其中启动udev的那些指令对于使用静态设备节点和devfs的系统不适用。
# Start udev /bin/mount -t tmpfs tmpfs /dev /sbin/udevd --daemon /sbin/udevstart
# Configure net interface /sbin/ifconfig lo 127.0.0.1 up /sbin/route add -net 127.0.0.0 netmask 255.0.0.0 lo /sbin/ifconfig eth0 192.168.2.25 netmask 255.255.255.0 /sbin/route add default gw 192.168.2.1
如果用的是udev,还必须有udev的配置脚本。这个写起来有些麻烦,我们可以直接用udev自己带的那些脚本,位置在udev目录下的etc/udev/udev.conf和etc/udev/rules.d里面的文件。把这些放到根文件系统中去,etc/udev/udev.conf变为根文件系统的/etc/udev/udev.conf,etc/udev/rules.d里面的文件变为/etc/udev/rules.d里面的文件。
12月19日
Network device support
网络设备
- Network device support
- 网络设备支持,当然要选啦
-
- Intermediate Functional Block support
- 这是一个中间层驱动,可以用来灵活的配置资源共享,看不懂的可以不选
- Dummy net driver support
- 哑接口网络,使用SLIP或PPP传输协议(如ADSL用户)的需要它
- Bonding driver support
- 将多个以太网通道绑定为一个,也就是两块网卡具有相同的IP地址并且聚合成一个逻辑链路工作,可以用来实现负载均衡或硬件冗余
- EQL (serial line load balancing) support
- 串行线路的负载均衡.如果有两个MODEM和两条电话线而且用SLIP或PPP协议,该选项可以让您同时使用这两个MODEM以达到双倍速度(在网络的另一端也要有同样的设备)
- Universal TUN/TAP device driver support
- TUN/TAP可以为用户空间提供包的接收和发送服务,比如可以用来虚拟一张网卡或点对点通道
- General Instruments Surfboard 1000
- SURFboard 1000插卡式Cable Medem(ISA接口),这玩意大概早就绝种了
- ARCnet devices
- 一般人没有ARCnet类型的网卡
- PHY device support
- 数据链路层芯片简称为MAC控制器,物理层芯片简称之为PHY,通常的网卡把MAC和PHY的功能做到了一颗芯片中,但也有一些仅含PHY的"软网卡"
- Ethernet (10 or 100Mbit)
- 目前最广泛的10/100M网卡
- Ethernet (1000 Mbit)
- 目前已成装机主流的1000M网卡
- Ethernet (10000 Mbit)
- 万兆网卡无福消受啦
- Token Ring devices
- 令牌环网设备
- Wireless LAN (non-hamradio)
- 无线LAN
- PCMCIA network device support
- PCMCIA或CardBus网卡
- Wan interfaces
- WAN接口
- ATM drivers
- 异步传输模式
- FDDI driver support
- 光纤分布式数据接口
- HIPPI driver support
- HIPPI(高性能并行接口)是一个在短距离内高速传送大量数据的点对点协议
- PLIP (parallel port) support
- 将并口映射成网络设备,这样两台机器即使没有网卡也可以使用并口通过并行线传输IP数据包
- PPP (point-to-point protocol) support
- 点对点协议,PPP已经基本取代SLIP了,用ADSL的可要仔细选择了
-
- PPP multilink support
- 多重链路协议(RFC1990)允许你将多个线路(物理的或逻辑的)组合为一个PPP连接一充分利用带宽,这不但需要pppd的支持,还需要ISP的支持
- PPP filtering
- 允许对通过PPP接口的包进行过滤
- PPP support for async serial ports
- 通过标准异步串口(COM1,COM2)使用PPP,比如使用老式的外置modem(非同步modem或ISDN modem)上网
- PPP support for sync tty ports
- 通过同步tty设备(比如SyncLink适配器)使用PPP,常用于高速租用线路(比如T1/E1)
- PPP Deflate compression
- 为PPP提供Deflate(等价于gzip压缩算法)压缩算法支持,需要通信双方的支持才有效
- PPP BSD-Compress compression
- 为PPP提供BSD(等价于LZW压缩算法,没有gzip高效)压缩算法支持,需要通信双方的支持才有效
- PPP MPPE compression (encryption)
- 为PPP提供MPPE加密协议支持,它被用于微软的P2P隧道协议中
- PPP over Ethernet
- 这就是ADSL用户最常见的PPPoE啦,也就是在以太网上跑的PPP协议
- PPP over ATM
- 在ATM上跑的PPP
- SLIP (serial line) support
- 一个在串行线上(例如电话线)传输IP数据报的TCP/IP协议.小猫一族的通讯协议,与宽带用户无关
-
- CSLIP compressed headers
- CSLIP协议比SLIP快,它将TCP/IP头(而非数据)进行压缩传送,需要通信双方的支持才有效
- Keepalive and linefill
- 让SLIP驱动支持RELCOM linefill和keepalive监视,这在信号质量比较差的模拟线路上是个好主意
- Six bit SLIP encapsulation
- 这种线路非常罕见,不要选它
- Fibre Channel driver support
- 光纤通道
- Traffic Shaper
- 流量整形,已废弃
- Network console logging support
- 通过网络记录内核信息
- Netpoll support for trapping incoming packets
- 不知道Netpoll是什么的可以不选
- Netpoll traffic trapping
- 不知道Netpoll是什么的可以不选
ISDN subsystem
综合业务数字网(Integrated Service Digital Network)
Telephony Support
VoIP支持
Input device support
输入设备
- Generic input layer (needed for keyboard,mouse...)
- 通用输入层,要使用键盘鼠标的就必选
-
- Support for memoryless force-feedback devices
- 游戏玩家使用的力反馈设备
- Mouse interface
- 鼠标接口
-
- Provide legacy /dev/psaux device
- 仍然支持作为传统的/dev/psaux设备
- Horizontal screen resolution
- 数字化转换器或图形输入板的水平分辩率
- Vertical screen resolution
- 数字化转换器或图形输入板的垂直分辨率
- Joystick interface
- 游戏杆
- Touchscreen interface
- 触摸屏
- Event interface
- 能够利用/dev/input/eventX来存取输入设备的事件
- Event debugging
- 该选项仅供调试
- Keyboards
- 键盘驱动,一般选个AT键盘即可
- Mouse
- 鼠标驱动,一般选个PS/2鼠标即可
- Joysticks
- 游戏杆驱动
- Touchscreens
- 触摸屏驱动
- Miscellaneous devices
- 其他杂项驱动,一般选个PC喇叭即可
- Hardware I/O ports
- 硬件I/O端口
-
- Serial I/O support
- 使用PS/2键盘或鼠标的就必选
-
- i8042 PC Keyboard controller
- PS/2接口的键盘和鼠标
- Serial port line discipline
- 串口键盘或鼠标
- ct82c710 Aux port controller
- 一种德州仪器TravelMate笔记本上使用QuickPort接口的鼠标
- Parallel port keyboard adapter
- 并口键盘或鼠标
- PCI PS/2 keyboard and PS/2 mouse controller
- 接在移动式扩展坞(Docking station)上的键盘或鼠标
- PS/2 driver library
- 为PS/2接口上的设备提供驱动(比如PS/2鼠标或标准AT键盘)
- Raw access to serio ports
- 不是hacker就别选了
- Gameport support
- 就是早年"小霸王"游戏机上的那种手柄
Character devices
字符设备
- Virtual terminal
- 虚拟终端.除非是嵌入式系统,否则必选
-
- Support for console on virtual terminal
- 内核将一个虚拟终端用作系统控制台(将诸如模块错误/内核错误/启动信息之类的警告信息发送到这里,通常是第一个虚拟终端).除非是嵌入式系统,否则必选
- Support for binding and unbinding console drivers
- 虚拟终端是通过控制台驱动程序与物理终端相结合的,但在某些系统上可以使用多个控制台驱动程序(如framebuffer控制台驱动程序),该选项使得你可以选择其中之一
- Non-standard serial port support
- 非标准串口支持.这样的设备早就绝种了
- Serial drivers
- 串口驱动.如果你有老式的串口鼠标或小猫之类的就选吧
- Unix98 PTY support
- 伪终端(PTY)可以模拟一个终端,它由slave(等价于一个物理终端)和master(被一个诸如xterms之类的进程用来读写slave设备)两部分组成的软设备.使用telnet或ssh远程登录者必选
- Legacy (BSD) PTY support
- 使用过时的BSD风格的/dev/ptyxx作为master,/dev/ttyxx作为slave,这个方案有一些安全问题,建议不选
- Parallel printer support
- 并口打印机
-
- Support for console on line printer
- 允许将内核信息输出到并口,这样就可以打印出来
- Support for user-space parallel port device drivers
- /dev/parport设备支持,比如deviceid之类的程序需要使用它,大部分人可以关闭该选项
- Texas Instruments parallel link cable support
- 德州仪器生产的一种使用并行电缆的图形计算器,如果你不知道这是什么设备就别选了
- IPMI
- 可以利用IPMI远程监视服务器的物理特征(温度,电压,风扇,电源,机箱入侵),它是独立于CPU,BIOS,OS的,只要接通电源就可以实现对服务器的监控
-
- IPMI top-level message handler
- IPMI消息处理器,要启用IPMI远程监视这个就必选
-
- Generate a panic event to all BMCs on a panic
- 当发生紧急情况(panic)时,IPMI消息处理器将会向每一个已注册的底板管理控制器(BMC)接口生成一个描述该panic的IPMI事件,这些事件可以引发日志记录/报警/重启/关机等动作
-
- Generate OEM events containing the panic string
- 当发生紧急情况(panic)时,IPMI消息处理器将会产生OEM类型的事件
- Device interface for IPMI
- 为IPMI消息处理器提供一个IOCTL接口已便用户空间的进程也可以使用IPMI
- IPMI System Interface handler
- 向系统提供接口(KCS,SMIC),一般你用了IPMI就需要选上
- IPMI Watchdog Timer
- 启用IPMI Watchdog定时器
- IPMI Poweroff
- 允许IPMI消息处理器关闭机器
- Watchdog Cards
- 能让系统在出现致命故障后自动重启,如果没有硬件Watchdog,建议使用Hangcheck timer而不是软件Watchdog
-
- Watchdog Timer Support
- 选中它并选中下面的一个Driver之后,再创建一个/dev/watchdog节点即可拥有一只Watchdog了.更多信息请参考内核帮助
-
- Disable watchdog shutdown on close
- 一旦Watchdog启动后就禁止将其停止
- Software watchdog
- 软件Watchdog,使用它不需要有任何硬件的支持,但是可靠性没有硬件Watchdog高
- {此处省略的硬件Watchdog部分请按照自己主板实际使用的芯片(可能在南桥中)进行选择}
- Hardware Random Number Generator Core support
- 硬件随机数发生器核心支持
-
- Intel HW Random Number Generator support
- Intel芯片组的硬件随机数发生器
- AMD HW Random Number Generator support
- AMD芯片组的硬件随机数发生器
- AMD Geode HW Random Number Generator support
- AMD Geode LX的硬件随机数发生器
- VIA HW Random Number Generator support
- VIA芯片组的硬件随机数发生器
- /dev/nvram support
- 直接存取主板上CMOS的接口,太危险了!建议别选
- Enhanced Real Time Clock Support
- 启用该选项并创建/dev/rtc文件后就可以通过/proc/driver/rtc访问系统的硬件时钟(RTC),众多功能依赖于它(如SMP,IRQ共享,定时器),建议选择
- Double Talk PC internal speech card support
- 由RC Systems公司制造的一种语音合成器
- Siemens R3964 line discipline
- 与使用西门子R3964协议的设备同步通信,除非你有一些诸如PLC之类的特殊设备,否则别选
- Applicom intelligent fieldbus card support
- Applicom international公司生产的用于现场总线连接卡
- Sony Vaio Programmable I/O Control Device support
- Sony VAIO笔记本上的东西
- Ftape, the floppy tape device driver
- 还使用磁带的就选吧
- /dev/agpgart (AGP Support)
- AGP总线支持,有AGP显卡的还必须从子项中选取符合自己显卡型号的驱动
- Direct Rendering Manager
- DRI允许应用程序以高效安全的方式直接访问图形处理,主要用于硬件3D加速.桌面用户建议选择,同时还必须从子项中选取符合自己显卡型号的驱动
- PCMCIA character devices
- 使用PCMCIA接口的字符设备,如果你有这种设备就到子项中去选吧
- ACP Modem (Mwave) support
- IBM Thinkpad上的一种软猫,古董产品
- NatSemi SCx200 GPIO Support
- 松下的一种通用输入输出(GPIO)芯片,常用于嵌入式系统
- NatSemi PC8736x GPIO Support
- 松下的一种通用输入输出(GPIO)芯片,常用于嵌入式系统
- NatSemi Base GPIO Support
- 松下的一种通用输入输出(GPIO)芯片,常用于嵌入式系统
- AMD CS5535/CS5536 GPIO
- 常用于AMD Geode的一种通用输入输出(GPIO)芯片,常用于嵌入式系统
- RAW driver (/dev/raw/rawN)
- 已废弃
- HPET - High Precision Event Timer
- 高精度事件定时器
-
- Allow mmap of HPET
- 允许对HPET寄存器进行映射,建议选中
- Hangcheck timer
- 宕机检测定时器周期性地检查系统任务调度程序以确定系统的运行状况,如果超过阈值,计算机将重新启动.它通常可以比Watchdog更好地解决可用性和可靠性问题
- TPM devices
- 基于硬件的"可信赖平台模块",与数字霸权管理是一路货,全不选
- Telecom clock driver for MPBL0010 ATCA SBC
- 没见过这种硬件,不选
I2C support
I2C是Philips极力推动的微控制应用中使用的低速串行总线协议,可用于监控电压/风扇转速/温度等.SMBus(系统管理总线)是I2C的子集.除硬件传感器外"Video For Linux"也需要该模块的支持
- I2C device interface
- I2C设备接口,允许用户空间的程序通过/dev/i2c-*设备文件使用I2C总线
- I2C Algorithms
- I2C算法,可以全不选,若有其他部分依赖其子项时,会自动选上
- I2C Hardware Bus support
- 按实际硬件情况选对应的子项即可
- Miscellaneous I2C Chip support
- 其他不常见的产品,按需选择
- I2C Core debugging messages
- 仅供调试
- I2C Algorithm debugging messages
- 仅供调试
- I2C Bus debugging messages
- 仅供调试
- I2C Chip debugging messages
- 仅供调试
SPI support
串行外围接口(SPI)常用于微控制器(MCU)与外围设备(传感器,eeprom,flash,编码器,模数转换器)之间的通信,比如MMC和SD卡就通常需要使用SPI
Dallas's 1-wire bus
一线总线
Hardware Monitoring support
当前主板大多都有一个监控硬件健康的设备用于监视温度/电压/风扇转速等,请按照自己主板实际使用的芯片选择相应的子项.另外,该功能还需要I2C的支持
Multimedia devices
多媒体设备
- Video For Linux
- 要使用音频/视频设备或FM收音卡的就必选,此功能还需要I2C的支持
- Enable Video For Linux API 1
- 使用老旧的V4L第一版API,反对使用
- Enable Video For Linux API 1 compatible Layer
- 提供对第一版V4L的兼容,建议不选
- Video Capture Adapters
- 视频捕获卡
-
- Enable advanced debug functionality
- 该选项仅供调试
- Autoselect pertinent encoders/decoders and other helper chips
- 为视频卡自动选择所需的编码和解码模块,建议选择
- Virtual Video Driver
- 虚拟视频卡,仅供测试视频程序和调试
- SAA5246A, SAA5281 Teletext processor
- 该选项仅对欧洲用户有意义,中国用户不需要
- SAA5249 Teletext processor
- 该选项仅对欧洲用户有意义,中国用户不需要
- {此处省略的硬件请按照自己实际使用的芯片进行选择}
- V4L USB devices
- 使用USB接口的视频卡,子项请按照自己实际使用的视频卡选择
- Radio Adapters
- 音频卡,子项请按照自己实际使用的音频卡选择
- Digital Video Broadcasting Devices
- 数字视频广播设备(DVB卡或机顶盒),子项请按自己实际使用的硬件选择
- DABUSB driver
- USB接口的数字音频广播设备接收器
Graphics support
图形设备/显卡支持
- Enable firmware EDID
- 允许访问Video BIOS中的扩展显示器识别数据(EDID),使用Matrox显卡的建议关闭,建议桌面用户选择
- Support for frame buffer devices
- 帧缓冲设备是为了让应用程序使用统一的接口操作显示设备而对硬件进行的抽象,建议桌面用户选择
-
- Enable Video Mode Handling Helpers
- 使用GTF和EDID来帮助处理显示模式,可以不选,若有其他选项依赖于它时,会自动选上
- Enable Tile Blitting Support
- 可以不选,若有其他选项依赖于它时,会自动选上
- VGA 16-color graphics support
- 16色VGA显卡.如果你有这种古董就选吧
- VESA VGA graphics support
- 符合VESA 2.0标准的显卡的通用驱动,如果显卡芯片在下面能够找到就可以不选
- {此处省略的硬件请按照自己实际使用的显卡芯片进行选择}
- Virtual Frame Buffer support
- 仅供调试使用
- Console display driver support
- 控制台显示驱动
-
- VGA text console
- 文本控制台,必选
-
- Enable Scrollback Buffer in System RAM
- 在内存中开辟额外的屏幕缓冲区,这将允许你回滚屏幕
-
- Scrollback Buffer Size (in KB)
- 在内存中开辟的额外屏幕缓冲区大小
- Video mode selection support
- 允许在内核启动时使用"vga="选择文本模式,如果你希望一行能够显示更多字符的话可以打开它
- MDA text console (dual-headed)
- 如果你有古董级别的单色显卡并且作为第二块显卡使用以实现双头显示就选上吧
- Framebuffer Console support
- 基于framebuffer的控制台驱动,服务器可以不选
-
- Framebuffer Console Rotation
- 显示画面旋转,它可能大大降低显示速度,建议不选
- Select compiled-in fonts
- 选择内建字体
-
- VGA 8x8 font
- 高分辨率下的小字体
- VGA 8x16 font
- 底分辨率下的大字体
- {其它字体省略}
- Logo configuration
- 启动时显示linux的logo(一幅企鹅图像),喜欢炫一下的就选吧
- Backlight & LCD device support
- LCD显示器支持,一般无需选择
Sound
声卡
- Advanced Linux Sound Architecture
- 使用声卡者必选
-
- Sequencer support
- 音序器支持(MIDI必需),除非你确定不需要,否则请选上
-
- Sequencer dummy client
- 除非你要同时连接到多个MIDI设备或应用程序,否则请不要选择
- OSS Mixer API
- OSS混音器API仿真,许多程序目前仍然需要使用它,建议选择
- OSS PCM (digital audio) API
- OSS数字录音(PCM)API模拟,许多程序目前仍然需要使用它,建议选择
-
- OSS PCM (digital audio) API - Include plugin system
- 建议不选
- OSS Sequencer API
- OSS音序器支持,许多程序目前仍然需要使用它,建议选择
- RTC Timer support
- 为ALSA启用RTC定时器支持,建议选择
-
- Use RTC as default sequencer timer
- 将RTC当作默认的时序脉冲发生器
- Dynamic device file minor numbers
- 仅供拥有多个声卡的用户选择
- Support old ALSA API
- 支持已被废弃的老版本ALSA API
- Verbose procfs contents
- 仅供调试使用
- Verbose printk
- 仅供调试使用
- Debug
- 仅供调试使用
- Generic devices
- 通用设备
-
- Dummy (/dev/null) soundcard
- 仅供调试
- Virtual MIDI soundcard
- 虚拟MIDI驱动,允许将使用原始MIDI设备的应用程序连接到音序器客户端,如果你不知道MIDI是什么就别选
- {此处省略的硬件请按照自己实际使用的声卡芯片进行选择}
- PCI devices
- PCI接口的声卡,请按实际使用的声卡选择子项
- USB devices
- USB接口的声卡,请按实际使用的声卡选择子项
- PCMCIA devices
- PCMCIA接口的声卡,请按实际使用的声卡选择子项
Open Sound System
反对使用
USB support
USB支持
- Support for Host-side USB
- 主机端(Host-side)USB支持.通用串行总线(USB)是一个串行总线子系统规范,它比传统的串口速度更快并且特性更丰富(供电,热插拔,最多可接127个设备等),有望在将来一统PC外设接口.USB的"Host"(主机)被称为"根"(也可以理解为是主板上的USB控制器),外部设备被称为"叶子",而内部的节点则称为"hub"(集线器).基本上只要你想使用任何USB设备都必须选中此项.另外,你还需要从下面选中至少一个"Host Controller Driver"(HCD),比如适用于USB1.1的"UHCI HCD support"或"OHCI HCD support",适用于USB2.0的"EHCI HCD (USB 2.0) support".如果你拿不准的话把他们全部选中一般也不会出问题.如果你的系统有设备端的USB接口(也就是你的系统可以作为"叶子"使用),请到"USB Gadget"中进行选择.
-
- USB verbose debug messages
- 仅供调试使用
- USB device filesystem
- 在/proc/bus/usb里列出当前连接的usb设备(mount -t usbfs none /proc/bus/usb),这样用户空间的程序就可以直接访问这些USB设备,基本上你要使用USB设备的话就必须选中此项
- Enforce USB bandwidth allocation
- 执行usb带宽分配限制,禁止打开占用usb总线带宽超过90%的设备,关闭该选项可能会导致某些设备无法正常工作
- Dynamic USB minor allocation
- 除非你有超过16个同类型的USB设备,否则不要选择
- USB selective suspend/resume and wakeup
- usb设备的挂起和恢复,毛病多多且许多设备尚未支持它,建议不选
- EHCI HCD (USB 2.0) support
- USB 2.0支持(大多数2002年以后的主板都支持).如果你选中了此项,一般来说你还需要选中OHCI或UHCI驱动
-
- Full speed ISO transactions
- 由于USB 2.0支持低速(1.5Mbps)/全速(12Mbps)/高速(480Mbps)三种规格的外部设备,为了将全/低速设备对高速设备可用带宽的影响减到最小,在USB2.0集线器中提供了一种事务转换(Transaction Translator)机制,该机制支持在Hub连接的是全/低速设备的情况下,允许主控制器与Hub之间以高速传输所有设备的数据,从而节省不必要的等待.如果你没有外置的USB集线器就无需选择
- Root Hub Transaction Translators
- 带有USB 2.0接口的主板上都有一个"根集线器"(Root Hub)以允许在无需额外购买hub的情况下就可以提供多个USB插口,其中的某些产品还在其中集成了事务转换(Transaction Translator)功能,这样就不需要再额外使用一个兼容OHCI或UHCI的控制器来兼容USB 1.1,即使你不太清楚自己主板上的根集线器是否集成了事务转换功能也可以安全的选中此项
- Improved Transaction Translator scheduling
- 如果你有一个高速USB 2.0 hub并且某些接在这个hub上的低速或全速设备不能正常工作(显示'cannot submit datapipe: error -28'或'error -71'错误),可以考虑选上
- ISP116X HCD support
- ISP1160/ISP1161主机USB控制器,是符合USB2.0全速规范的单片主机控制器和设备控制器,支持OHCI标准
- OHCI HCD support
- 开放主机控制接口(OHCI)是主要针对嵌入式系统的USB 1.1主机控制器规范
- UHCI HCD (most Intel and VIA) support
- 通用主机控制器接口(UHCI)是主要针对PC机的USB 1.1主机控制器规范.另外,EHCI也可能需要它
- Elan U132 Adapter Host Controller
- 如果你有这种硬件就选吧
- SL811HS HCD support
- 如果你有这种硬件就选吧
- USB Bluetooth TTY support
- USB蓝牙TTY设备支持
- USB MIDI support
- USB MIDI设备支持
- USB Modem (CDC ACM) support
- USB接口的猫或ISDN适配器
- USB Printer support
- USB打印机
USB Mass Storage support
USB存储设备(U盘,USB硬盘,USB软盘,USB CD-ROM,USB磁带,memory sticks,数码相机,读卡器等等).该选项依赖于'SCSI device support',且大部分情况下还依赖于'SCSI disk support'(比如U盘或USB硬盘)
- USB Mass Storage verbose debug
- 仅供调试使用
- {省略的部分请按照自己实际使用的硬件选择(事实上大部分人都没有这些设备,可以全不选)}
The shared table of common (or usual) storage devices
该模块包含一张记录了常用USB存储设备及其驱动的表格,这样你无需重新编译模块即可在切换这些设备时自动邦定对应的驱动(还需要对/etc/modprobe.conf进行相应的设置).不确定的建议不选
USB Human Interface Device (full HID) support
USB人机界面设备(鼠标/键盘/游戏杆/手写版等人操作计算机的设备),该驱动不能和"USB HID Boot Protocol drivers"同时使用
- HID input layer support
- 如果你有USB接口的鼠标/键盘/游戏杆/手写板等输入设备就必选
-
- Enable support for iBook/PowerBook special keys
- 苹果iBooks/PowerBooks键盘上的Fn/Numlock等功能键支持
- Force feedback support
- 力反馈设备
- /dev/hiddev raw HID device support
- 如果你有USB监控装置或不间断电源(UPS)之类的非输入设备就选上
- USB HID Boot Protocol drivers
- 如果你有绝对的把握确信不为自己的键盘和鼠标使用通常的HID驱动,而要使用Boot Protocol模式的HID驱动(常见于嵌入式环境)就选吧
Aiptek 6000U/8000U tablet support
一种手写板
Wacom Intuos/Graphire tablet support
一种手写/绘图板
Acecad Flair tablet support
一种数控绘图板
KB Gear JamStudio tablet support
一种手写/绘图板
Griffin PowerMate and Contour Jog support
一种具有调节音量/滚动文本/视频快进快退等功能的产品
USB Touchscreen Driver
USB触摸屏驱动
Yealink usb-p1k voip phone
一种VoIP电话
X-Box gamepad support
X-Box游戏板
ATI / X10 USB RF remote control
一种usb远程控制设备
ATI / Philips USB RF remote control
一种usb远程控制设备
Keyspan DMR USB remote control
一种usb远程控制设备
Apple USB Touchpad support
苹果机上的触摸板
USB Mustek MDC800 Digital Camera support
一种数码相机
Microtek X6USB scanner support
一种扫描仪
USB Network Adapters
USB网络适配器,如果你有这种设备请按自己实际使用的硬件选择子项
USB Monitor
usb流量监控,一般没必要选它
USS720 parport driver
一种USB接口转并口的转换设备
USB Serial Converter support
USB接口转串口的转换设备
EMI 6|2m USB Audio interface support
一种USB音频设备
EMI 2|6 USB Audio interface support
一种USB音频设备
ADU devices from Ontrak Control Systems
Ontrak Control Systems公司的一种自动拨号设备
USB Auerswald ISDN support
一种ISDN设备
USB Diamond Rio500 support
一种mp3播放机
USB Lego Infrared Tower support
一种无线发射机
USB LCD driver support
USB液晶显示器
USB LED driver support
USB发光二极管
Cypress CY7C63xxx USB driver support
德国AK Modul-Bus Computer GmbH公司的一种产品,不知道是用来干什么的
Cypress USB thermometer driver support
一种温度计??
USB Phidgets drivers
来自Phidgets公司的各种USB产品
Siemens ID USB Mouse Fingerprint sensor support
西门子公司的一种指纹传感器
Elan PCMCIA CardBus Adapter USB Client
Elan公司的一种USB转PCMCIA的适配器
Apple Cinema Display support
苹果公司的一种Cinema Display
USB 2.0 SVGA dongle support (Net2280/SiS315)
一种软件狗
USB LD driver
USB LD驱动
PlayStation 2 Trance Vibrator driver support
SONY的PS2上面的"入迷振荡器"(类似于力反馈手柄)
USB testing driver
测试中的驱动,别选
USB DSL modem support
USB DSL猫
USB Gadget Support
其他各种杂七杂八的usb小玩艺
MMC/SD Card support
MMC/SD卡支持
LED devices
发光二级管(LED)设备
InfiniBand support
InfiniBand是一个通用的高性能I/O规范,它使得存储区域网中以更低的延时传输I/O消息和集群通讯消息并且提供很好的伸缩性.用于Linux服务器集群系统
EDAC - error detection and reporting (RAS)
错误检测与纠正(EDAC)的目标是发现并报告甚至纠正在计算机系统中发生的错误,这些错误是由CPU或芯片组报告的底层错误(内存错误/缓存错误/PCI错误/温度过高,等等),建议选择.如果这些代码报告了一个错误,请到http://bluesmoke.sourceforge.net/和http://buttersideup.com/edacwiki查看更多信息
- Debugging
- 仅供调试使用
- Main Memory EDAC (Error Detection And Correction) reporting
- 一些系统能够检测和修正主内存中的错误,EDAC能够报告这些信息(EDAC自己检测到的或者根据ECC得到的).EDAC还会尽量检测这些错误发生在哪里以便于替换损坏的内存.建议选择并按照你实际使用的芯片组选取子项
- Error detecting method
- 错误检测方法,当前只有一个"Poll for errors"(错误轮询)可用
Real Time Clock
所有的PC机主板都包含一个电池动力的实时时钟芯片,以便在断电后仍然能够继续保持时间,RTC通常与CMOS集成在一起,因此BIOS可以从中读取当前时间
- RTC class
- 通用RTC类支持,选中此项后你就可以在操作系统中使用一个或多个RTC设备(你还必须从下面启用一个或多个RTC接口)
-
- Set system time from RTC on startup
- 系统启动时使用从指定的RTC设备中读取的时间来设定系统时间,通常这将有助于避免不必要的文件系统检测程序(fsck)的运行,建议选择
-
- The RTC to read the time from
- 指定具体从哪个RTC设备中读取时间
- RTC debug support
- 仅供调试使用
- sysfs
- 允许通过sysfs接口使用RTC,允许多个RTC设备,也就是/sys/class/rtc/rtc0~N
- proc
- 允许通过proc接口使用RTC,仅允许一个RTC设备,也就是/proc/driver/rtc
- dev
- 允许通过dev接口使用RTC,允许多个RTC设备,也就是"udev"设置的/dev/rtc0~N,建议你建立一个指向其中之一的软连接/dev/rtc,某些程序(比如hwclock)需要使用/dev/rtc
-
- RTC UIE emulation on dev interface
- 如果底层rtc芯片驱动没有提供RTC_UIE就仿真一个RTC_UIE.那些请求将产生每秒一次的更新请求以用来同步[这个选项的意思我也搞不清楚究竟时啥意思,翻译的也可能有误]
- {此处省略的RTC驱动请按照自己实际使用的RTC芯片进行选择}
DMA Engine support
从Intel Bensley双核服务器平台开始引入的数据移动加速(Data Movement Acceleration)引擎,它将某些传输数据的操作从CPU转移到专用硬件,从而可以进行异步传输并减轻CPU负载.Intel已将此项技术变为开放的标准,将来应当会有更多的厂商支持
- Network: TCP receive copy offload
- 通过在网络栈中利用DMA引擎来减少接收数据包时的copy-to-user操作以释放CPU资源,这是DMA引擎目前最主要的用途
- Intel I/OAT DMA support
- Intel I/O加速技术(Intel I/O Acceleration Technology)中的DMA支持,基于Intel Bensley的新一代服务器平台都支持它
File systems 文件系统 强烈建议在选择之前先看看各种文件系统的比较
- Second extended fs support
- Ext2文件系统是Linux的标准文件系统,擅长处理稀疏文件
-
- Ext2 extended attributes
- Ext2文件系统扩展属性(与inode关联的name:value对)支持
-
- Ext2 POSIX Access Control Lists
- POSIX ACL(访问控制列表)支持,可以更精细的针对每个用户进行访问控制,需要外部库和程序的支持
- Ext2 Security Labels
- 安全标签允许选择使用不同的安全模型实现(如SELinux)的访问控制模型,如果你没有使用需要扩展属性的安全模型就别选
- Ext2 execute in place support
- 程序在写入存储介质时就已经分配好运行时的地址,因此不需要载入内存即可在芯片内执行,一般仅在嵌入式系统上才有这种设备
- Ext3 journalling file system support
- Ext3性能平庸,使用journal日志模式时数据完整性非常好(但怪异的是此时多线程并发读写速度却最快)
-
- Ext3 extended attributes
- Ext3文件系统扩展属性(与inode关联的name:value对)支持
-
- Ext3 POSIX Access Control Lists
- POSIX ACL(访问控制列表)支持,可以更精细的针对每个用户进行访问控制,需要外部库和程序的支持
- Ext3 Security Labels
- 安全标签允许选择使用不同的安全模型实现(如SELinux)的访问控制模型,如果你没有使用需要扩展属性的安全模型就别选
- Ext4dev/ext4 extended fs support
- 尚处于开发状态的Ext4
- JBD (ext3) debugging support
- 仅供开发者使用
- JBD2 (ext4dev/ext4) debugging support
- 仅供开发者使用
- Reiserfs support
- 性能几乎全面超越Ext2(处理稀疏文件比Ext2慢),小文件(小于4k)性能非常突出,创建和删除文件速度最快,处理大量目录和文件(5k-20k)时仍然非常迅速.日志模式建议使用Ordered,追求极速可使用Writeback模式,追求安全可使用Journal模式.建议使用noatime,notail选项挂载分区以提高速度和避免bug.用于NFS和磁盘限额时需要额外的补丁
-
- Enable reiserfs debug mode
- 启用ReiserFS调试模式,仅供开发者使用
- Stats in /proc/fs/reiserfs
- 在/proc/fs/reiserfs文件中显示Reiserfs文件系统的状态,仅供开发者使用
- ReiserFS extended attributes
- ReiserFS文件系统扩展属性(与inode关联的name:value对)支持
-
- ReiserFS POSIX Access Control Lists
- POSIX ACL(访问控制列表)支持,可以更精细的针对每个用户进行访问控制,需要外部库和程序的支持
- ReiserFS Security Labels
- 安全标签允许选择使用不同的安全模型实现(如SELinux)的访问控制模型,如果你没有使用需要扩展属性的安全模型就别选了
- JFS filesystem support
- IBM的JFS文件系统
- XFS filesystem support
- 碎片最少,多线程并发读写最佳,大文件(>64k)性能最佳,创建和删除文件速度较慢.由于XFS在内存中缓存尽可能多的数据且仅当内存不足时才会将数据刷到磁盘,所以应当仅在确保电力供应不会中断的情况下才使用XFS
-
- Quota support
- XFS的磁盘配额支持
- Security Label support
- 扩展的安全标签支持.SElinux之类的安全系统会使用到这样的扩展安全属性
- POSIX ACL support
- POSIX ACL(访问控制列表)支持,可以更精细的针对每个用户进行访问控制,需要外部库和程序的支持
- Realtime support
- 实时子卷是专门存储文件数据的卷,可以允许将日志与数据分开在不同的磁盘上
GFS2 file system support
一种用于集群的文件系统
OCFS2 file system support
一种用于集群的文件系统
Minix fs support
老古董文件系统
ROM file system support
用于嵌入式系统的内存文件系统的支持
Inotify file change notification support
新式的文件系统的变化通知机制,简洁而强大,用于代替老旧的Dnotify
- Inotify support for userspace
- 用户空间的Inotify支持
Quota support
磁盘配额支持,限制某个用户或者某组用户的磁盘占用空间,Ext2/Ext3/Reiserfs都支持它
- Old quota format support
- 老式的配额格式支持
- Quota format v2 support
- 新的v2格式允许使用32位的UID/GID
Dnotify support
旧式的基于目录的文件变化的通知机制(新机制是Inotify),目前仍然有一些程序依赖它
Kernel automounter support
内核自动加载远程文件系统(v3,就算选也不选这个旧的)
Kernel automounter version 4 support (also supports v3)
新的(v4)的内核自动加载远程文件系统的支持,也支持v3
Filesystem in Userspace support
FUSE允许在用户空间实现一个文件系统,如果你打算开发一个自己的文件系统或者使用一个基于FUSE的文件系统就选吧
CD-ROM/DVD Filesystems
CD-ROM/DVD文件系统
- ISO 9660 CDROM file system support
- CD-ROM的标准文件系统
-
- Microsoft Joliet CDROM extensions
- Microsoft对ISO 9660文件系统的Joliet扩展,允许在文件名中使用Unicode字符,也允许长文件名
- Transparent decompression extension
- Linux对ISO 9660文件系统的扩展,允许将数据透明的压缩存储在CD上
- UDF file system support
- 某些新式CD/DVD上的文件系统,很少见
DOS/FAT/NT Filesystems
DOS/Windows的文件系统
- MSDOS fs support
- 古老的MSDOS文件系统
- VFAT (Windows-95) fs support
- 从Win95开始使用的VFAT文件系统
-
- Default codepage for FAT
- 默认代码页
- Default iocharset for FAT
- 默认字符集
- NTFS file system support
- 从WinNT开始使用的NTFS文件系统
-
- NTFS debugging support
- 仅供调试使用
- NTFS write support
- NTFS写入支持
Pseudo filesystems
伪文件系统
- /proc file system support
- 显示系统状态的虚拟文件系统(irq设置,内存使用,加载的设备驱动器,网络状态等),许多程序依赖于它
-
- /proc/kcore support
- 系统物理内存的映象
- /proc/vmcore support
- 以ELF格式转储的已崩溃内核镜像,仅供调试使用
- Sysctl support (/proc/sys)
- 显示各种不同的内核参数,并让root用户能交互地更改其中的某些内容
- sysfs file system support
- 导出内核内部对象及其属性和对象之间的相互关系的文件系统,它把连接在系统上的设备和总线以及驱动程序等组织成为一个分级的文件,内核启动时依靠它挂载根分区,禁用sysfs后必须在内核引导参数中使用设备号指定根分区
- Virtual memory file system support (former shm fs)
- tmpfs文件系统(以前叫shm[共享内存]文件系统)支持
-
- Tmpfs POSIX Access Control Lists
- POSIX ACL(访问控制列表)支持,可以更精细的针对每个用户进行访问控制,需要外部库和程序的支持
- HugeTLB file system support
- 大多数现代计算机体系结构提供对多种内存页面大小的支持(比如IA-32结构支持4K和4M(PAE模式为2M)两种页面).TLB(Translation Lookaside Buffer)是虚拟地址到物理地址的翻译缓冲区,这种缓冲区在处理器上是很宝贵的,操作系统总是尝试将有限的TLB资源发挥到极致.特别是能够轻松获得若干G内存的时候(>4G),这种优化就显得尤为关键.只有开启此选项之后才能提供hugepage支持.
- Userspace-driven configuration filesystem
- configfs是用户空间驱动的文件系统,提供与sysfs相反的功能
Miscellaneous filesystems
非主流的杂项文件系统
Network File Systems
网络文件系统
Partition Types
高级磁盘分区类型,不确定可以全不选
Native Language Support
本地语言支持
- Base native language support
- 基础本地语言,必选
-
- Default NLS Option
- 默认本地语言,建议使用UTF-8
- {此处省略的部分请按需选择,一般至少需要CP437,ASCII,ISO-8859-1}
Distributed Lock Manager
通用的分布式锁管理器,不明白就不选
Instrumentation Support 分析支持
- Profiling support
- 对系统的活动进行分析,仅供内核开发者使用
- Kprobes
- 仅供内核开发者使用
Kernel hacking 内核hack选项
- Show timing information on printks
- 在printk的输出中包含时间信息,可以用来分析内核启动过程各步骤所用时间
- Enable __must_check logic
- 在编译内核的过程中使用"必须检查"的逻辑,禁用它将不会显示某些警告信息
- Magic SysRq key
- 不懂的千万别选
- Enable unused/obsolete exported symbols
- 导出无用和废弃的符号,这将使内核不必要的增大
- Kernel debugging
- 不是内核开发者的别选
- Debug Filesystem
- 不是内核开发者的别选
- Compile the kernel with frame unwind information
- 不是内核开发者的别选
- Run 'make headers_check' when building vmlinux
- 在编译内核时运行'make headers_check'命令检查内核头文件,当你修改了与用户空间相关的内核头文件后建议启用该选项
- Linux Kernel Dump Test Tool Module
- 不是内核开发者的别选
- Enable doublefault exception handler
- 允许捕获非常罕见的导致系统无警告重启的doublefault异常,对于调试非常重要
Security options 安全选项 这里的选项不明白的建议不要选,否则有可能弄巧成拙.
- Enable access key retention support
- 在内核中保留authentication token和access key
-
- Enable the /proc/keys file by which keys may be viewed
- 允许有权限的进程通过/proc/keys读取所有的key
- Enable different security models
- 允许内核选择不同的安全模型,如果未选中则内核将使用默认的安全模型
-
- Socket and Networking Security Hooks
- 允许安全模型通过Security Hook对Socket与Networking进行访问控制
-
- XFRM (IPSec) Networking Security Hooks
- 启用XFRM安全Hook
- Default Linux Capabilities
- 启用与"默认"Linux的兼容性
- Root Plug Support
- 一个简单的Linux安全模块,在特定的USB设备不存在时它简单的禁止一切egid==0的进程运行
- NSA SELinux Support
- 美国国家安全局(NSA)开发的安全增强Linux(SELinux),你还需要进行策略配置(checkpolicy)并且对文件系统进行标记(setfiles)
-
- NSA SELinux boot parameter
- 添加一个内核引导参数以允许在引导时使用'selinux=0'禁用SELinux或'selinux=1'启用SELinux
-
- NSA SELinux boot parameter default value
- 上述参数的默认值
- NSA SELinux runtime disable
- 允许在运行时禁用SELinux
- NSA SELinux Development Support
- SELinux开发支持
- NSA SELinux AVC Statistics
- 搜集存取向量(access vector)缓冲区的统计信息并在/selinux/avc/cache_stats中显示出来.这些信息可以用avcstat之类的工具查看
- NSA SELinux checkreqprot default value
- checkreqprot标志的默认值
- NSA SELinux enable new secmark network controls by default
- 默认启用新的基于安全标记(secmark)的网络
- NSA SELinux maximum supported policy format version
- 允许将支持的最高策略格式版本设置为一个特定的数值
-
- NSA SELinux maximum supported policy format version value
- 支持的最高策略格式版本的数值
Cryptographic options 加密选项
- Cryptographic API
- 提供核心的加密API支持.这里的加密算法被广泛的应用于驱动程序通信协议等机制中.子选项可以全不选,内核中若有其他部分依赖它,会自动选上
-
- Cryptographic algorithm manager
- 创建加密模版实例,必须要选
- HMAC support
- 为IPSec所必须,可为PPPoE提供压缩支持
- Null algorithms
- NULL加密算法(什么也不做),用于IPsec协议的封装安全载荷模块(ESP)
- MD4 digest algorithm
- 老旧的摘要算法,已经过时
- MD5 digest algorithm
- 主流摘要算法,128位(已被中国山东大学王小云攻破,可以快速找到碰撞)
- SHA1 digest algorithm
- 主流摘要算法,160位(已被中国山东大学王小云攻破,可以快速找到碰撞),速度与MD5相当
- SHA256 digest algorithm
- 更好的摘要算法,256位,速度较SHA1稍慢
- SHA384 and SHA512 digest algorithms
- 更好的摘要算法,384/512位,速度大约只有SHA1的40-50%
- Whirlpool digest algorithms
- 最安全的摘要算法,512位,已被列入ISO标准,目前最新版本为3.0(2003年发布)
- Tiger digest algorithms
- 号称最快的摘要算法,192位,专门为64位CPU进行了优化
- ECB support
- 电子密码本,最简单的加密方法
- CBC support
- 密码块链,IPSec需要使用它
- DES and Triple DES EDE cipher algorithms
- 老迈的(DES)和尚佳的(Triple DES)对称加密算法
- Blowfish cipher algorithm
- 又老又慢的对称加密算法
- Twofish cipher algorithm
- 很强的对称加密算法,使用较广
- Twofish cipher algorithms (i586)
- 很强的对称加密算法,使用较广(针对i586的版本)
- Serpent cipher algorithm
- 很强的对称加密算法
- AES cipher algorithms
- 最佳的对称加密算法(Rijndael),128/192/256位,强度最高,快速且节省内存
- AES cipher algorithms (i586)
- 最佳的对称加密算法(Rijndael),128/192/256位,强度最高,快速且节省内存(针对i586的版本)
- CAST5 (CAST-128) cipher algorithm
- 对称加密算法
- CAST6 (CAST-256) cipher algorithm
- 对称加密算法
- TEA, XTEA and XETA cipher algorithms
- 较弱的对称加密算法
- ARC4 cipher algorithm
- 脆弱的流对称加密算法
- Khazad cipher algorithm
- 对称加密算法
- Anubis cipher algorithm
- 对称加密算法
- Deflate compression algorithm
- 压缩算法,当在IPSec中使用IPCOMP协议时才需要
- Michael MIC keyed digest algorithm
- 摘要算法,仅仅用于校验iSCSI设备传输的数据,因为算法本身比较脆弱
- CRC32c CRC algorithm
- 摘要算法,可用于校验iSCSI设备传输的数据
- Testing module
- 快速且丑陋的测试模块
- Hardware crypto devices
- 仅有VIA C7系列处理器支持硬件加密(VIA PadLock高级加密引擎)
Library routines 库子程序 仅有那些不包含在内核原码中的第三方内核模块才可能需要,可以全不选,内核中若有其他部分依赖它,会自动选上
- CRC-CCITT functions
- 传送8-bit字符,欧洲标准
- CRC16 functions
- 传送8-bit字符,美国标准
- CRC32 functions
- 用于点对点的同步数据传输中,传输网络数据包所必须的
- CRC32c (Castagnoli, et al) Cyclic Redundancy-Check
- 用于点对点的同步数据传输中,比如iSCSI设备
- Load an Alternate Configuration File
- 读入一个外部配置文件
- Save Configuration to an Alternate File
- 将配置保存到一个外部文件
这篇文章主要写的是x86体系下的配置,不过很多选项和ARM是一样的。
Linux 2.6.19.x 内核编译配置选项简介
版权声明
本文作者是一位自由软件爱好者,所以本文虽然不是软件,但是本着 GPL 的精神发布。任何人都可以自由使用、转载、复制和再分发,但必须保留作者署名,亦不得对声明中的任何条款作任何形式的修改,也不得附加任何其它条件。您可以自由链接、下载、传播此文档,但前提是必须保证全文完整转载,包括完整的版权信息和作译者声明。
其他作品
本文作者十分愿意与他人共享劳动成果,如果你对我的其他翻译作品或者技术文章有兴趣,可以在如下位置查看现有作品的列表:
BUG报告,切磋与探讨
由于作者水平有限,因此不能保证作品内容准确无误,请在阅读中自行鉴别。如果你发现了作品中的错误,请您来信指出,哪怕是错别字也好,任何提高作品质量的建议我都将虚心接纳。如果你愿意就作品中的相关内容与我进行进一步切磋与探讨,也欢迎你与我联系。联系方式:Email: csfrank@citiz.net ; QQ: 70171448 ; MSN: csfrank122@hotmail.com
本文作者将不定期的根据最新的内核进行添加(同时仍然保留老版本内核的选项),欢迎常来光临并帮助指出其中的错误.
Code maturity level options 代码成熟度选项
- Prompt for development and/or incomplete code/drivers
- 显示尚在开发中或尚未完成的代码与驱动.除非你是测试人员或者开发者,否则请勿选择
General setup 常规设置
- Local version - append to kernel release
- 在内核版本后面加上自定义的版本字符串(小于64字符),可以用"uname -a"命令看到
- Automatically append version information to the version string
- 自动在版本字符串后面添加版本信息,编译时需要有perl以及git仓库支持
- Support for paging of anonymous memory (swap)
- 使用交换分区或者交换文件来做为虚拟内存
- System V IPC
- System V进程间通信(IPC)支持,许多程序需要这个功能.必选,除非你知道自己在做什么
-
- IPC Namespaces
- IPC命名空间支持,不确定可以不选
- POSIX Message Queues
- POSIX消息队列,这是POSIX IPC中的一部分
- BSD Process Accounting
- 将进程的统计信息写入文件的用户级系统调用,主要包括进程的创建时间/创建者/内存占用等信息
-
- BSD Process Accounting version 3 file format
- 使用新的第三版文件格式,可以包含每个进程的PID和其父进程的PID,但是不兼容老版本的文件格式
- Export task/process statistics through netlink
- 通过netlink接口向用户空间导出任务/进程的统计信息,与BSD Process Accounting的不同之处在于这些统计信息在整个任务/进程生存期都是可用的
-
- Enable per-task delay accounting
- 在统计信息中包含进程等候系统资源(cpu,IO同步,内存交换等)所花费的时间
- UTS Namespaces
- UTS名字空间支持,不确定可以不选
- Auditing support
- 审计支持,某些内核模块(例如SELinux)需要它,只有同时选择其子项才能对系统调用进行审计
-
- Enable system-call auditing support
- 支持对系统调用的审计
- Kernel .config support
- 把内核的配置信息编译进内核中,以后可以通过scripts/extract-ikconfig脚本来提取这些信息
-
- Enable access to .config through /proc/config.gz
- 允许通过/proc/config.gz访问内核的配置信息
- Cpuset support
- 只有含有大量CPU(大于16个)的SMP系统或NUMA(非一致内存访问)系统才需要它
- Kernel->user space relay support (formerly relayfs)
- 在某些文件系统上(比如debugfs)提供从内核空间向用户空间传递大量数据的接口
- Initramfs source file(s)
- initrd已经被initramfs取代,如果你不明白这是什么意思,请保持空白
- Optimize for size (Look out for broken compilers!)
- 编译时优化内核尺寸(使用"-Os"而不是"-O2"参数编译),有时会产生错误的二进制代码
- Enable extended accounting over taskstats
- 收集额外的进程统计信息并通过taskstats接口发送到用户空间
- Configure standard kernel features (for small systems)
- 配置标准的内核特性(为小型系统)
-
- Enable 16-bit UID system calls
- 允许对UID系统调用进行过时的16-bit包装
- Sysctl syscall support
- 不需要重启就能修改内核的某些参数和变量,如果你也选择了支持/proc,将能从/proc/sys存取可以影响内核行为的参数或变量
- Load all symbols for debugging/kksymoops
- 装载所有的调试符号表信息,仅供调试时选择
-
- Include all symbols in kallsyms
- 在kallsyms中包含内核知道的所有符号,内核将会增大300K
- Do an extra kallsyms pass
- 除非你在kallsyms中发现了bug并需要报告这个bug才打开该选项
- Support for hot-pluggable devices
- 支持热插拔设备,如usb与pc卡等,Udev也需要它
- Enable support for printk
- 允许内核向终端打印字符信息,在需要诊断内核为什么不能运行时选择
- BUG() support
- 显示故障和失败条件(BUG和WARN),禁用它将可能导致隐含的错误被忽略
- Enable ELF core dumps
- 内存转储支持,可以帮助调试ELF格式的程序
- Enable full-sized data structures for core
- 在内核中使用全尺寸的数据结构.禁用它将使得某些内核的数据结构减小以节约内存,但是将会降低性能
- Enable futex support
- 快速用户空间互斥体可以使线程串行化以避免竞态条件,也提高了响应速度.禁用它将导致内核不能正确的运行基于glibc的程序
- Enable eventpoll support
- 支持事件轮循的系统调用
- Use full shmem filesystem
- 完全使用shmem来代替ramfs.shmem是基于共享内存的文件系统(可能用到swap),在启用TMPFS后可以挂载为tmpfs供用户空间使用,它比简单的ramfs先进许多
- Use full SLAB allocator
- 使用SLAB完全取代SLOB进行内存分配,SLAB是一种优秀的内存分配管理器,推荐使用
- Enable VM event counters for /proc/vmstat
- 允许在/proc/vmstat中包含虚拟内存事件记数器
Loadable module support 可加载模块支持
- Enable loadable module support
- 打开可加载模块支持,如果打开它则必须通过"make modules_install"把内核模块安装在/lib/modules/中
-
- Module unloading
- 允许卸载已经加载的模块
-
- Forced module unloading
- 允许强制卸载正在使用中的模块(比较危险)
- Module versioning support
- 允许使用其他内核版本的模块(可能会出问题)
- Source checksum for all modules
- 为所有的模块校验源码,如果你不是自己编写内核模块就不需要它
- Automatic kernel module loading
- 让内核通过运行modprobe来自动加载所需要的模块,比如可以自动解决模块的依赖关系
Block layer 块设备层
- Enable the block layer
- 块设备支持,使用硬盘/USB/SCSI设备者必选
-
- Support for Large Block Devices
- 仅在使用大于2TB的块设备时需要
- Support for tracing block io actions
- 块队列IO跟踪支持,它允许用户查看在一个块设备队列上发生的所有事件,可以通过blktrace程序获得磁盘当前的详细统计数据
- Support for Large Single Files
- 仅在可能使用大于2TB的文件时需要
- IO Schedulers
- IO调度器
-
- Anticipatory I/O scheduler
- 假设一个块设备只有一个物理查找磁头(例如一个单独的SATA硬盘),将多个随机的小写入流合并成一个大写入流,用写入延时换取最大的写入吞吐量.适用于大多数环境,特别是写入较多的环境(比如文件服务器)
- Deadline I/O scheduler
- 使用轮询的调度器,简洁小巧,提供了最小的读取延迟和尚佳的吞吐量,特别适合于读取较多的环境(比如数据库)
- CFQ I/O scheduler
- 使用QoS策略为所有任务分配等量的带宽,避免进程被饿死并实现了较低的延迟,可以认为是上述两种调度器的折中.适用于有大量进程的多用户系统
- Default I/O scheduler
- 默认IO调度器
Processor type and features 中央处理器(CPU)类型及特性
- Symmetric multi-processing support
- 对称多处理器支持,如果你有多个CPU或者使用的是多核CPU就选上.此时"Enhanced Real Time Clock Support"选项必须开启,"Advanced Power Management"选项必须关闭
- Subarchitecture Type
- 处理器的子架构,大多数人都应当选择"PC-compatible"
- Processor family
- 处理器系列,请按照你实际使用的CPU选择
- Generic x86 support
- 通用x86支持,如果你的CPU能够在上述"Processor family"中找到就别选
- HPET Timer Support
- HPET是替代8254芯片的新一代定时器,i686及以上级别的主板都支持,可以安全的选上
- Maximum number of CPUs
- 支持的最大CPU数,每增加一个内核将增加8K体积
- SMT (Hyperthreading) scheduler support
- 支持Intel的超线程(HT)技术
- Multi-core scheduler support
- 针对多核CPU进行调度策略优化
- Preemption Model
- 内核抢占模式
-
- No Forced Preemption (Server)
- 适合服务器环境的禁止内核抢占
- Voluntary Kernel Preemption (Desktop)
- 适合普通桌面环境的自愿内核抢占
- Preemptible Kernel (Low-Latency Desktop)
- 适合运行实时程序的主动内核抢占
- Preempt The Big Kernel Lock
- 可以抢占大内核锁,应用于实时要求高的场合,不适合服务器环境
- Machine Check Exception
- 让CPU检测到系统故障时通知内核,以便内核采取相应的措施(如过热关机等)
-
- Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4
- 每5秒检测一次这些cpu的非致命错误并纠正它们,同时记入日志
- check for P4 thermal throttling interrupt
- 当P4的cpu过热时显示一条警告消息
- Enable VM86 support
- 虚拟X86支持,在DOSEMU下运行16-bit程序或XFree86通过BIOS初始化某些显卡的时候才需要
- Toshiba Laptop support
- Toshiba笔记本模块支持
- Dell laptop support
- Dell笔记本模块支持
- Enable X86 board specific fixups for reboot
- 修正某些旧x86主板的重起bug,这种主板基本绝种了
- /dev/cpu/microcode - Intel IA32 CPU microcode support
- 使用不随Linux内核发行的IA32微代码,你必需有IA32微代码二进制文件,仅对Intel的CPU有效
- /dev/cpu/*/msr - Model-specific register support
- 在多cpu系统中让特权CPU访问x86的MSR寄存器
- /dev/cpu/*/cpuid - CPU information support
- 能从/dev/cpu/x/cpuid获得CPU的唯一标识符(CPUID)
- Firmware Drivers
- 固件驱动程序
-
- BIOS Enhanced Disk Drive calls determine boot disk
- 有些BIOS支持从某块特定的硬盘启动(如果BIOS不支持则可能无法启动),目前大多数BIOS还不支持
- BIOS update support for DELL systems via sysfs
- 仅适用于DELL机器
- Dell Systems Management Base Driver
- 仅适用于DELL机器
- High Memory Support
- 最高内存支持,总内存小于等于1G的选"off",大于4G的选"64G"
- Memory split
- 如果你不是绝对清楚自己在做什么,不要改动这个选项
- Memory model
- 一般选"Flat Memory",其他选项涉及内存热插拔
- 64 bit Memory and IO resources
- 使用64位的内存和IO资源
- Allocate 3rd-level pagetables from highmem
- 在内存很多(大于4G)的机器上将用户空间的页表放到高位内存区,以节约宝贵的低端内存
- Math emulation
- 数学协处理器仿真,486DX以上的cpu就不要选它了
- MTRR (Memory Type Range Register) support
- 打开它可以提升PCI/AGP总线上的显卡2倍以上的速度,并且可以修正某些BIOS错误
- Boot from EFI support
- EFI是一种可代替传统BIOS的技术(目前的Grub/LILO尚不能识别它),但是现在远未普及
- Enable kernel irq balancing
- 让内核将irq中断平均分配给多个CPU以进行负载均衡,但是要配合irqbanlance守护进程才行
- Use register arguments
- 使用"-mregparm=3"参数编译内核,将前3个参数以寄存器方式进行参数调用,可以生成更紧凑和高效的代码
- Enable seccomp to safely compute untrusted bytecode
- 只有嵌入式系统可以不选
- Timer frequency
- 内核时钟频率,桌面推荐"1000 HZ",服务器推荐"100 HZ"或"250 HZ"
- kexec system call
- 提供kexec系统调用,可以不必重启而切换到另一个内核
- kernel crash dumps
- 被kexec启动后产生内核崩溃转储
- Physical address where the kernel is loaded
- 内核加载的物理地址,除非你知道自己在做什么,否则不要修改.在提供kexec系统调用的情况下可能要修改它
- Support for hot-pluggable CPUs
- 对热插拔CPU提供支持
- Compat VDSO support
- 如果Glibc版本大于等于2.3.3就不选,否则就选上
Power management options 电源管理选项
- Power Management support
- 电源管理有APM和ACPI两种标准且不能同时使用.即使关闭该选项,X86上运行的Linux也会在空闲时发出HLT指令将CPU进入睡眠状态
-
- Legacy Power Management API
- 传统的电源管理API,比如软关机和系统休眠等接口
- Power Management Debug Support
- 仅供调试使用
- Driver model /sys/devices/.../power/state files
- 内核帮助文档反对使用该选项,即将被废除
- ACPI (Advanced Configuration and Power Interface) Support
- 必须运行acpid守护程序ACPI才能起作用.ACPI是为了取代APM而设计的,因此应该尽量使用ACPI而不是APM
-
- AC Adapter
- 如果你的系统可以在AC和电池之间转换就可以选
- Battery
- 通过/proc/acpi/battery向用户提供电池状态信息,用电池的笔记本可以选
- Button
- 守护程序捕获Power,Sleep,Lid按钮事件,并根据/proc/acpi/event做相应的动作,软件控制的poweroff需要它
- Video
- 仅对集成在主板上的显卡提供ACPI2.0支持,且不是所有集成显卡都支持
- Generic Hotkey
- 统一的热键驱动,建议不选
- Fan
- 允许通过用户层的程序来对系统风扇进行控制(开,关,查询状态),支持它的硬件并不多
- Dock
- 支持由ACPI控制的集线器(docking stations)
- Processor
- 让ACPI处理空闲状态,并使用ACPI C2和C3处理器状态在空闲时节省电能,同时它还被cpufreq的"Performance-state drivers"选项所依赖
-
- Thermal Zone
- 系统温度过高时可以利用ACPI thermal zone及时调整工作状态以避免你的CPU被烧毁
- ASUS/Medion Laptop Extras
- ASUS笔记本专用,以提供额外按钮的支持,用户可以通过/proc/acpi/asus来打开或者关闭LCD的背光/调整亮度/定制LED的闪烁指示等功能
- IBM ThinkPad Laptop Extras
- IBM ThinkPad专用
- Toshiba Laptop Extras
- Toshiba笔记本专用
- Disable ACPI for systems before Jan 1st this year
- 输入四位数的年份,在该年的1月1日前不使用ACPI的功能("0"表示一直使用)
- Debug Statements
- 详细的ACPI调试信息,不搞开发就别选
- Power Management Timer Support
- 这个Timer在所有ACPI兼容的平台上都可用,且不会受PM功能的影响,建议总是启用它.如果你在kernel log中看到了'many lost ticks'那就必须启用它
- ACPI0004,PNP0A05 and PNP0A06 Container Driver
- 支持内存和CPU的热插拔
- Smart Battery System
- 支持依赖于I2C的"智能电池".这种电池非常老旧且罕见,还与当前的ACPI标准兼容性差
APM (Advanced Power Management) BIOS Support
APM在SMP机器上必须关闭,一般来说当前的笔记本都支持ACPI,所以应尽量关闭该该选项
- Ignore USER SUSPEND
- 只有NEC Versa M系列的笔记本才需要选择这一项
- Enable PM at boot time
- 系统启动时即启用APM,选上这个选项能让系统自动的进行电源管理,但常常导致启动时死机
- Make CPU Idle calls when idle
- 系统空闲时调用空闲指令(halt),只有老式的CPU才需要选它,且对于SMP系统必须关闭
- Enable console blanking using APM
- 在屏幕空白时关闭LCD背光,事实上对所有的笔记本都无效
- RTC stores time in GMT
- 将硬件时钟应该设为格林威治时间,否则视为本地时间.建议你使用GMT,这样你无须为时区的改变而担心
- Allow interrupts during APM BIOS calls
- 允许APM的BIOS调用时中断,IBM Thinkpad的一些新机器需要这项.如果休眠时挂机(包括睡下去就醒不来),可以试试它
- Use real mode APM BIOS call to power off
- 此驱动为某些有Bug的BIOS准备,如果你的系统不能正常关机或关机时崩溃,可以试试它
CPU Frequency scaling
允许动态改变CPU主频,达到省电和降温的目的,必须同时启用下面的一种governor才行
- Enable CPUfreq debugging
- 允许对CPUfreq进行调试
- CPU frequency translation statistics
- 通过sysfs文件系统输出CPU频率变换的统计信息
-
- CPU frequency translation statistics details
- 输出详细的CPU频率变换统计信息
- Default CPUFreq governor
- 默认的CPU频率调节器
- 'performance' governor
- '性能'优先,静态的将频率设置为cpu支持的最高频率
- 'powersave' governor
- '节能'优先,静态的将频率设置为cpu支持的最低频率
- 'userspace' governor for userspace frequency scaling
- 既允许手动调整cpu频率,也允许用户空间的程序动态的调整cpu频率(需要额外的调频软件,比如cpufreqd)
- 'ondemand' cpufreq policy governor
- '立即响应',周期性的考察CPU负载并自动的动态调整cpu频率(不需要额外的调频软件),适合台式机
- 'conservative' cpufreq governor
- '保守',和'ondemand'相似,但是频率的升降是渐变式的(幅度不会很大),更适合用于笔记本/PDA/AMD64环境
- ACPI Processor P-States driver
- 将ACPI2.0的处理器性能状态报告给CPUFreq processor drivers以决定如何调整频率,该选项依赖于ACPI->Processor
- {省略的部分请按照自己实际使用的CPU选择}
- /proc/acpi/processor/../performance interface
- 内核帮助文档反对使用该选项,即将被废除
- Relaxed speedstep capability checks
- 放松对系统的speedstep兼容性检查,仅在某些老旧的Intel系统上需要打开
Bus options (PCI, PCMCIA, EISA, MCA, ISA) 总线选项
- PCI support
- PCI支持,如果使用了PCI或PCI Express设备就必选
-
- PCI access mode
- PCI访问模式,强列建议选"Any"(系统将优先使用"MMConfig",然后使用"BIOS",最后使用"Direct"检测PCI设备)
- PCI Express support
- PCI Express支持(目前主要用于显卡和千兆网卡)
-
- PCI Express Hotplug driver
- 如果你的主板和设备都支持PCI Express热插拔就可以选上
-
- Use polling mechanism for hot-plug events
- 对热插拔事件采用轮询机制,仅用于测试目的
- Root Port Advanced Error Reporting support
- 由PCI Express AER驱动程序处理发送到Root Port的错误信息
- Message Signaled Interrupts (MSI and MSI-X)
- PCI Express支持两类中断:INTx使用传统的IRQ中断,可以与现行的PCI总线的驱动程序和操作系统兼容;MSI则是通过inbound Memory Write触发和发送中断,更适合多CPU系统.可以使用"pci=nomsi"内核引导参数关闭MSI
- PCI Debugging
- 将PCI调试信息输出到系统日志里
- Interrupts on hypertransport devices
- 允许本地的hypertransport设备使用中断
- ISA support
- 现在基本上没有ISA的设备了,如果你有就选吧
- MCA support
- 微通道总线,老旧的IBM的台式机和笔记本上可能会有这种总线
- NatSemi SCx200 support
- 在使用AMD Geode处理器的机器上才可能有
- PCCARD (PCMCIA/CardBus) support
- PCMCIA卡(主要用于笔记本)支持
-
- Enable PCCARD debugging
- 仅供调试
- 16-bit PCMCIA support
- 一些老的PCMCIA卡使用16位的CardBus
- 32-bit CardBus support
- 当前的PCMCIA卡基本上都是32位的CardBus
- CardBus yenta-compatible bridge support
- 使用PCMCIA卡的基本上都需要选择这一项,子项请按照自己实际使用的PCMCIA卡选择
- {省略的部分请按照自己实际使用的PCMCIA卡选择}
- PCI Hotplug Support
- PCI热插拔支持,如果你有这样的设备就到子项中去选吧
Executable file formats 可执行文件格式
- Kernel support for ELF binaries
- ELF是开放平台下最常用的二进制文件格式,支持动态连接,支持不同的硬件平台.除非你知道自己在做什么,否则必选
- Kernel support for a.out and ECOFF binaries
- 早期UNIX系统的可执行文件格式,目前已经被ELF格式取代
- Kernel support for MISC binaries
- 允许插入二进制的封装层到内核中,使用Java,.NET,Python,Lisp等语言编写的程序时需要它
Networking 网络
- Networking options
- 网络选项
-
- Network packet debugging
- 在调试不合格的包时加上额外的附加信息,但在遇到Dos攻击时你可能会被日志淹没
- Packet socket
- 这种Socket可以让应用程序(比如tcpdump,iptables)直接与网络设备通讯,而不通过内核中的其它中介协议
-
- Packet socket: mmapped IO
- 让Packet socket驱动程序使用IO映射机制以使连接速度更快
- Unix domain sockets
- 一种仅运行于本机上的效率高于TCP/IP的Socket,简称Unix socket.许多程序都使用它在操作系统内部进行进程间通信(IPC),比如X Window和syslog
- Transformation user configuration interface
- 为IPsec(可在ip层加密)之类的工具提供XFRM用户配置接口支持
- Transformation sub policy support
- XFRM子策略支持,仅供开发者使用
- PF_KEY sockets
- 用于可信任的密钥管理程序和操作系统内核内部的密钥管理进行通信,IPsec依赖于它
- TCP/IP networking
- TCP/IP协议当然要选
-
- IP: multicasting
- 群组广播,似乎与网格计算有关,仅在使用MBONE的时候才需要
- IP: advanced router
- 高级路由,如果想做一个路由器就选吧
- IP: policy routing
- 策略路由
- IP: equal cost multipath
- 用于路由的基于目的地址的负载均衡
- IP: verbose route monitoring
- 显示冗余的路由监控信息
- IP: kernel level autoconfiguration
- 在内核启动时自动配置ip地址/路由表等,需要从网络启动的无盘工作站才需要这个东西
- IP: tunneling
- IP隧道,将一个IP报文封装在另一个IP报文内的技术
- IP: GRE tunnels over IP
- 基于IP的GRE(通用路由封装)隧道
- IP: multicast routing
- 多重传播路由
- IP: ARP daemon support
- 这东西尚处于试验阶段就已经被废弃了
- IP: TCP syncookie support
- 抵抗SYN flood攻击的好东西,要启用它必须同时启用/proc文件系统和"Sysctl support",然后在系统启动并挂载了/proc之后执行"echo 1 >/proc/sys/net/ipv4/tcp_syncookies"命令
- IP: AH transformation
- IPsec验证头(AH)实现了数据发送方的验证处理,可确保数据既对于未经验证的站点不可用也不能在路由过程中更改
- IP: ESP transformation
- IPsec封闭安全负载(ESP)实现了发送方的验证处理和数据加密处理,用以确保数据不会被拦截/查看或复制
- IP: IPComp transformation
- IPComp(IP静荷载压缩协议),用于支持IPsec
- IP: IPsec transport mode
- IPsec传输模式,常用于对等通信,用以提供内网安全.数据包经过了加密但IP头没有加密,因此任何标准设备或软件都可查看和使用IP头
- IP: IPsec tunnel mode
- IPsec隧道模式,用于提供外网安全(包括虚拟专用网络).整个数据包(数据头和负载)都已经过加密处理且分配有新的ESP头/IP头和验证尾,从而能够隐藏受保护站点的拓扑结构
- IP: IPsec BEET mode
- IPsec BEET模式
- INET: socket monitoring interface
- socket监视接口,一些Linux本地工具(如:包含ss的iproute2)需要使用它
- TCP: advanced congestion control
- 高级拥塞控制,如果没有特殊需求(比如无线网络)就别选了,内核会自动将默认的拥塞控制设为"Cubic"并将"Reno"作为候补
- IP: Virtual Server Configuration
- IP虚拟服务器允许你基于多台物理机器构建一台高性能的虚拟服务器,不玩集群就别选了
- The IPv6 protocol
- 你要是需要IPv6就选吧
- NetLabel subsystem support
- NetLabel子系统为诸如CIPSO与RIPSO之类能够在分组信息上添加标签的协议提供支持,如果你看不懂就别选了
Security Marking
对网络包进行安全标记,类似于nfmark,但主要是为安全目的而设计,如果你不明白的话就别选
Network packet filtering (replaces ipchains)
Netfilter可以对数据包进行过滤和修改,可以作为防火墙("packet filter"或"proxy-based")或网关(NAT)或代理(proxy)或网桥使用.选中此选项后必须将"Fast switching"关闭,否则将前功尽弃
- Network packet filtering debugging
- 仅供开发者调试Netfilter使用
- Bridged IP/ARP packets filtering
- 如果你希望使用一个针对桥接的防火墙就打开它
- Core Netfilter Configuration
- 核心Netfilter配置(当包流过Chain时如果match某个规则那么将由该规则的target来处理,否则将由同一个Chain中的下一个规则进行匹配,若不match所有规则那么最终将由该Chain的policy进行处理)
-
- Netfilter netlink interface
- 允许Netfilter在与用户空间通信时使用新的netlink接口.netlink Socket是Linux用户态与内核态交流的主要方法之一,且越来越被重视.
-
- Netfilter NFQUEUE over NFNETLINK interface
- 通过NFNETLINK接口对包进行排队
- Netfilter LOG over NFNETLINK interface
- 通过NFNETLINK接口对包记录.该选项废弃了ipt_ULOG和ebg_ulog机制,并打算在将来废弃基于syslog的ipt_LOG和ip6t_LOG模块
- Layer 3 Independent Connection tracking
- 独立于第三层的链接跟踪,通过广义化的ip_conntrack支持其它非IP协议的第三层协议
- Netfilter Xtables support
- 如果你打算使用ip_tables,ip6_tables,arp_tables之一就必须选上
-
- "CLASSIFY" target support
- 允许为包设置优先级,一些排队规则(atm,cbq,dsmark,pfifo_fast,htb,prio)需要使用它
- "CONNMARK" target support
- 类似于"MARK",但影响的是连接标记的值
- "DSCP" target support
- 允许对ip包头部的DSCP(Differentiated Services Codepoint)字段进行修改,该字段常用于Qos
- "MARK" target support
- 允许对包进行标记(通常配合ip命令使用),这样就可以改变路由策略或者被其它子系统用来改变其行为
- "NFQUEUE" target Support
- 用于替代老旧的QUEUE(iptables内建的target之一),因为NFQUEUE能支持最多65535个队列,而QUEUE只能支持一个
- "NOTRACK" target support
- 允许规则指定哪些包不进入链接跟踪/NAT子系统
- "SECMARK" target support
- 允许对包进行安全标记,用于安全子系统
- "CONNSECMARK" target support
- 针对链接进行安全标记,同时还会将连接上的标记还原到包上(如果链接中的包尚未进行安全标记),通常与SECMARK target联合使用
- "comment" match support
- 允许你在iptables规则集中加入注释
- "connbytes" per-connection counter match support
- 允许针对单个连接内部每个方向(进/出)匹配已经传送的字节数/包数
- "connmark" connection mark match support
- 允许针对每个会话匹配先前由"CONNMARK"设置的标记值
- "conntrack" connection tracking match support
- 连接跟踪匹配,是"state"的超集,它允许额外的链接跟踪信息,在需要设置一些复杂的规则(比如网关)时很有用
- "DCCP" protocol match support
- DCCP是打算取代UDP的新传输协议,它在UDP的基础上增加了流控和拥塞控制机制,面向实时业务
- "DSCP" match support
- 允许对IP包头的DSCP字段进行匹配
- "ESP" match support
- 允许对IPSec包中的ESP头进行匹配,使用IPsec的话就选上吧
- "helper" match support
- 加载特定协议的连接跟踪辅助模块,由该模块过滤所跟踪的连接类型的包,比如ip_conntrack_ftp模块
- "length" match support
- 允许对包的长度进行匹配
- "limit" match support
- 允许根据包的进出速率进行规则匹配,常和"LOG target"配合使用以抵抗某些Dos攻击
- "mac" address match support
- 允许根据以太网的MAC进行匹配,常用于无线网络环境
- "mark" match support
- 允许对先前由"MARK"标记的特定标记值进行匹配
- IPsec "policy" match support
- 使用IPsec就选上吧
- Multiple port match support
- 允许对TCP或UDP包同时匹配多个端口(通常情况下只能匹配一个端口)
- "physdev" match support
- 允许对到达的或将要离开的物理桥端口进行匹配
- "pkttype" packet type match support
- 允许对封包目的地址类别(广播/群播/直播)进行匹配
- "quota" match support
- 允许对总字节数的限额值进行匹配
- "realm" match support
- 允许对iptables中的路由子系统中的realm值进行匹配
- "sctp" protocol match support
- 流控制传输协议(SCTP),十年以后也许能够普及的东西
- "state" match support
- 这是对包进行分类的有力工具,它允许利用连接跟踪信息对连接中处于特定状态的包进行匹配
- "statistic" match support
- 允许根据一个给定的百分率对包进行周期性的或随机性的匹配
- "string" match support
- 允许根据包所承载的数据中包含的特定字符串进行匹配
- "tcpmss" match support
- 允许根据TCP SYN包头中的MSS(最大分段长度)选项的值进行匹配
IP: Netfilter Configuration
针对IPv4的Netfilter配置
- Connection tracking (required for masq/NAT)
- 链接跟踪.可用于报文伪装或地址转换,也可用于增强包过滤能力
-
- Connection tracking flow accounting
- 允许针对每个连接记录已经传送的字节/包数,常用于connbytes match
- Connection mark tracking support
- 允许对连接进行标记,与针对单独的包进行标记的不同之处在于它是针对连接流的.CONNMARK target和connmark match需要它的支持
- Connection tracking security mark support
- 允许对连接进行安全标记,通常这些标记包(SECMARK)复制到其所属连接(CONNSECMARK),再从连接复制到其关联的包(SECMARK)
- Connection tracking events
- 连接跟踪事件支持.如果启用这个选项,连接跟踪代码将提供一个notifier链,它可以被其它内核代码用来获知连接跟踪状态的改变
- Connection tracking netlink interface
- 支持基于netlink的用户空间接口
- SCTP protocol connection tracking support
- SCTP是IP网面向多媒体通信的新一代的流控制传输协议
- FTP protocol support
- FTP协议
- IRC protocol support
- IRC协议是一种用来实时聊天协议,用过mIRC的人应当不陌生
- NetBIOS name service protocol support
- NetBIOS名字服务协议
- TFTP protocol support
- TFTP是基于UDP的比FTP简单的文件传输协议
- Amanda backup protocol support
- Amanda备份协议
- PPTP protocol support
- 点对点隧道协议(PPTP)是一种支持多协议虚拟专用网络的网络技术,ADSL用户对它应该很熟悉
- H.323 protocol support
- ITU-T提出的用于IP电话的协议
- SIP protocol support
- IETE提出的用于IP电话的协议
IP Userspace queueing via NETLINK
已废弃
IP tables support (required for filtering/masq/NAT)
要用iptables就肯定要选上
- IP range match support
- 允许对ip地址的范围进行匹配
- TOS match support
- 允许对ip包头的TOS(Type Of Service)字段进行匹配
- recent match support
- 可以创建一个或多个刚刚使用过的ip地址列表,然后根据这些列表进行匹配
- ECN match support
- 允许对TCP/IP包头的ECN(Explicit Congestion Notification)字段进行匹配.ECN是一种显式拥塞通知技术,它不但要求路由器支持而且要求端到端主机的支持,其基本思想是当路由器发生早期拥塞时不是丢弃包而是尽量对包进行标记,接收方接到带有ECN提示的包时,通知发送方网络即将发生拥塞,也就是它通过对包的标记提示TCP源即将发生拥塞,从而引发拥塞避免算法
- AH match support
- 允许对IPSec包头的AH字段进行匹配
- TTL match support
- 允许对ip包头的TTL(生存期)字段进行匹配
- Owner match support
- 允许对本地生成的包按照其宿主(user,group,process,session)进行匹配
- address type match support
- 允许对地址类型(单播,本地,广播)进行匹配
- hashlimit match support
- 是limit的升级,它基于你选择的ip地址与/或端口动态的创建以limit为桶(bucket)的哈希表.它可以创建诸如"为每个特定的目标IP分配10kpps"或"允许每个特定的源IP分配500pps"之类的规则
- Packet filtering
- 定义filter表以允许对包进行过滤
-
- REJECT target support
- 允许返回一个ICMP错误而不是简单的丢弃包
- LOG target support
- 允许将符合条件的包头信息通过syslog进行记录
- ULOG target support
- 透过netlink socket将符合条件的封包交给用户空间的ulogd守护进程.反对使用该选项,因为它已经被NETFILTER_NETLINK_LOG代替
- TCPMSS target support
- 允许修改TCP包头中的MSS(最大分段长度)选项值
- Full NAT
- 允许进行伪装/端口转发以及其它的NAT功能,仅在你需要使用iptables中的nat表时才需要选择
- Packet mangling
- 在iptables中启用mangle表以便对包进行各种修改,常用于改变包的路由
- raw table support (required for NOTRACK/TRACE)
- 在iptables中添加一个'raw'表,该表在netfilter框架中非常靠前,并在PREROUTING和OUTPUT链上有钩子,从而可以对收到的数据包在连接跟踪前进行处理
ARP tables support
ARP表支持.只有在局域网中才有ARP欺骗问题,另外路由器也会遭到ARP欺骗
- ARP packet filtering
- ARP包过滤.对于进入和离开本地的ARP包定义一个filter表,在桥接的情况下还可以应用于被转发ARP包
- ARP payload mangling
- 允许对ARP包的荷载部分进行修改,比如修改源和目标物理地址
IPv6: Netfilter Configuration
针对IPv6的Netfilter配置,需要的话可以参考前面IPv4的Netfilter配置进行选择
DECnet: Netfilter Configuration
针对DECnet的Netfilter配置
Bridge: Netfilter Configuration
针对桥接的Netfilter配置
DCCP Configuration
数据报拥塞控制协议在UDP的基础上增加了流控和拥塞控制机制,使数据报协议能够更好地用于流媒体业务的传输
SCTP Configuration
流控制传输协议是一种新兴的传输层协议.TCP协议一次只能连接一个IP地址而在SCTP协议一次可以连接多个IP地址且可以自动平衡网络负载,一旦某一个IP地址失效会自动将网络负载转移到其他IP地址上
TIPC Configuration
透明内部进程间通信协议,以共享内存为基础实现任务和资源的调度,专门用于内部集群通信
Asynchronous Transfer Mode (ATM)
异步传输模式(ATM)支持
802.1d Ethernet Bridging
802.1d以太网桥
802.1Q VLAN Support
802.1Q虚拟局域网
DECnet Support
DECnet是一种很生僻的协议
ANSI/IEEE 802.2 LLC type 2 Support
看不懂可以不选
The IPX protocol
IPX协议
Appletalk protocol support
与Mac机器通信的协议
CCITT X.25 Packet Layer
大约没人需要这东西
LAPB Data Link Driver
大约没人需要这东西
Acorn Econet/AUN protocols
一种被Acorn计算机使用的又老又慢的协议
WAN router
广域网路由
QoS and/or fair queueing
如果你需要Qos或公平队列就选吧
Network testing
网络测试,仅供调试使用
Amateur Radio support
业余无线电支持
IrDA (infrared) subsystem support
红外线支持,比如无线鼠标或无线键盘
Bluetooth subsystem support
蓝牙支持
Generic IEEE 802.11 Networking Stack
通用无线局域网(IEEE 802.11系列协议)支持
Device Drivers 设备驱动程序
- Generic Driver Options
- 驱动程序通用选项
-
- Select only drivers that don't need compile-time external firmware
- 只显示那些不需要内核对外部设备的固件作map支持的驱动程序,除非你有某些怪异硬件,否则请选上
- Prevent firmware from being built
- 不编译固件.固件一般是随硬件的驱动程序提供的,仅在更新固件的时候才需要重新编译.建议选上
- Userspace firmware loading support
- 提供某些内核之外的模块需要的用户空间固件加载支持,在内核树之外编译的模块可能需要它
- Driver Core verbose debug messages
- 让驱动程序核心在系统日志中产生冗长的调试信息,仅供调试
Connector - unified userspace <-> kernelspace linker
统一的用户空间和内核空间连接器,工作在netlink socket协议的顶层.不确定可以不选
- Report process events to userspace
- 向用户空间报告进程事件(fork,exec,id变化(uid,gid,suid)
Memory Technology Devices (MTD)
特殊的存储技术装置,如常用于数码相机或嵌入式系统的闪存卡
Parallel port support
并口支持(传统的打印机接口)
Plug and Play support
即插即用支持,若未选则应当在BIOS中关闭"PnP OS".这里的选项与PCI设备无关
- PnP Debug Messages
- 该选项仅供调试使用
- ISA Plug and Play support
- ISA设备即插即用支持
- Plug and Play BIOS support
- Linux使用"Plug and Play BIOS"规范v1.0A(1994年)中定义的PNPBIOS自动检测主板上的资源和设备,但是其中的某些特性目前尚未实现,比如:事件通知/扩展坞(Docking Station)信息/ISAPNP服务.如果你希望由内核检测主板上的设备并为其分配资源(此时BIOS中的"PnP OS"必须开启)可以选上,此外,PNPBIOS还有助于防止主板上的设备与其他总线设备冲突.不过需要注意的是ACPI将会逐渐取代PNPBIOS(虽然目前两者可以共存),所以如果你的系统不使用ISA设备并且支持ACPI,建议你不要选中该选项并将BIOS中的"PnP OS"关闭
-
- Plug and Play BIOS /proc interface
- 该选项仅供调试使用
- Plug and Play ACPI support
- 让Linux使用PNPACPI自动检测主板上内建的设备并为其分配资源(即使这些设备已被BIOS禁用),它有助于避免设备之间的资源(如中断)冲突
Block devices
块设备
- Normal floppy disk support
- 通用软驱支持
- XT hard disk support
- 古董级产品
- Parallel port IDE device support
- 通过并口与计算机连接的IDE设备,比如某些老旧的外接光驱或硬盘之类
- Compaq SMART2 support
- 基于Compaq SMART2控制器的磁盘阵列卡
- Compaq Smart Array 5xxx support
- 基于Compaq SMART控制器的磁盘阵列卡
- Mylex DAC960/DAC1100 PCI RAID Controller support
- 古董级产品
- Micro Memory MM5415 Battery Backed RAM support
- 一种使用电池做后备电源的内存
- Loopback device support
- Loopback是指拿文件来模拟块设备,比如可以将一个iso9660镜像文件挂成一个文件系统
-
- Cryptoloop Support
- 使用系统提供的加密API对Loopback设备加密,但不能用于日志型文件系统
- Network block device support
- 让你的电脑成为网络块设备的客户端
- Promise SATA SX8 support
- 基于Promise公司的SATA SX8控制器的RAID卡
- Low Performance USB Block driver
- 它不是用来支持U盘的,不懂的就别选
- RAM disk support
- 内存中的虚拟磁盘,大小固定(由下面的选项决定,也可给内核传递"ramdisk_size=参数"来决定),它的功能和代码都比shmem简单许多
-
- Default number of RAM disks
- 默认RAM disk的数量
- Default RAM disk size (kbytes)
- 仅在你真正知道它的含义时才允许修改
- Default RAM disk block size (bytes)
- 每一个RAM disk的默认块大小,设为PAGE_SIZE的值时效率最高
Initial RAM filesystem and RAM disk (initramfs/initrd) support
如果启动计算机所必须的模块都在内核里的话可以不选此项
Packet writing on CD/DVD media
CD/DVD刻录支持
- Free buffers for data gathering
- 用于收集写入数据的缓冲区个数(每个占用64Kb内存),缓冲区越多性能越好
- Enable write caching
- 为CD-R/W设备启用写入缓冲,目前这是一个比较危险的选项
ATA over Ethernet support
以太网ATA设备支持
Misc devices
杂项设备
ATA/ATAPI/MFM/RLL support
通常是IDE硬盘和ATAPI光驱.纯SCSI系统且不使用这些接口可以不选
- Max IDE interfaces
- 最大IDE接口数,两个IDE插槽一般相当于4个接口
- Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support
- EIDE支持是当然要选的,否则540MB以上的硬盘都不认识而且不支持主从设备
-
- Support for SATA (deprecated; conflicts with libata SATA driver)
- 反对使用,该选项与libata SATA驱动有冲突
- Use old disk-only driver on primary interface
- 没人用这些古董了
- Include IDE/ATA-2 DISK support
- ATA-2支持,除非你的硬盘是古董,否则必选
- Use multi-mode by default
- 如果不确定就别选,除非出现帮助中指出的错误
- PCMCIA IDE support
- 通过PCMCIA卡与计算机连接的IDE设备,比如某些外置硬盘或光驱
- Include IDE/ATAPI CDROM support
- 有IDE光驱的就选
- Include IDE/ATAPI TAPE support
- 有IDE磁带的就选
- Include IDE/ATAPI FLOPPY support
- 有IDE软驱的就选
- SCSI emulation support
- SCSI仿真,以前刻录光碟时需要,现在不需要了
- IDE Taskfile Access
- 对介质进行直接的原始访问,它是一个复杂且有效的测试和校验硬件的方案,可以在驱动层之下执行数据恢复工作
- generic/default IDE chipset support
- 通用IDE芯片组支持
- CMD640 chipset bugfix/support
- 586以前的主板上常用,毛病多多
- PNP EIDE support
- 外接的即插即用EIDE卡支持
- PCI IDE chipset support
- 基于PCI总线的IDE芯片组支持,帮助IDE驱动自动检测和配置所有基于PCI的IDE接口
-
- Sharing PCI IDE interrupts support
- 与其他PCI设备共享中断,一来可能冲突,二来降低性能,不选为妙
- Boot off-board chipsets first support
- 不使用外接IDE控制器的就别选,使用外接IDE控制器的注意看帮助
- Generic PCI IDE Chipset Support
- 通用的PCI IDE芯片组支持,如果你的芯片组在下面能找到就别选
- OPTi 82C621 chipset enhanced support
- OPTi 82C621 EIDE控制器
- RZ1000 chipset bugfix/support
- 486/586年代的玩艺
- Generic PCI bus-master DMA support
- 通用的PCI总线控制器DMA支持,586以上的系统都支持
-
- Force enable legacy 2.0.X HOSTS to use DMA
- 历史遗留问题,别管它,不选
- Use PCI DMA by default when available
- 默认启用DMA,586以上的系统都支持,建议选择
-
- Enable DMA only for disks
- 只对硬盘启用DMA,若你的光驱不支持DMA就选上
- {此处省略的部分按照自己主板上实际使用的芯片组进行选择}
- Other IDE chipset support
- 其它IDE芯片组支持(多数需要在引导时指定特定的内核参数),如果你使用这样的芯片组就按实际情况选择子项吧
- IGNORE word93 Validation BITS
- ATA-4和ATA-5规范中对于如何在80针的数据线上探测解释的不明确,导致了两种不同标准的产品同时出现,这可能导致ATA-66/100降低为ATA-33,若出现这个问题,可以打开这个选项忽略这种不同,但是又有可能导致另外的问题
- Old hard disk (MFM/RLL/IDE) driver
- 旧版本的MFM/RLL/IDE驱动,不建议使用
SCSI device support
SCSI设备
- RAID Transport Class
- 用于SCSI设备的软件RAID支持,需要配合外部工具
- SCSI device support
- 有任何SCSI/SATA/USB/光纤/FireWire/IDE-SCSI仿真设备之一就必须选上
- legacy /proc/scsi/ support
- 一些老的刻录程序可能需要它
- SCSI disk support
- SCSI硬盘或U盘
- SCSI tape support
- SCSI磁带
- SCSI OnStream SC-x0 tape support
- 另一种SCSI磁带
- SCSI CDROM support
- SCSI CDROM
-
- Enable vendor-specific extensions
- 仅在古董级的SCSI CDROM设备上才需要
- SCSI generic support
- 若有SCSI硬盘/CD-ROM/tape之外的SCSI设备才需要选择
- SCSI media changer support
- 一种SCSI备份设备
- Probe all LUNs on each SCSI device
- 在每个SCSI设备上探测逻辑设备数.只在一个SCSI设备上有多个逻辑设备(模拟多个SCSI设备,比如多口读卡器)时才需要选它,一般的SCSI设备不需要
- Verbose SCSI error reporting
- 以易读的方式报告SCSI错误,内核将会增大12K
- SCSI logging facility
- 启用SCSI日志(默认并不开启,需要在挂载/proc后执行echo "scsi log token [level]" > /proc/scsi/scsi命令才能打开日志),可用于跟踪和捕获SCSI设备的错误
- SCSI Transports
- SCSI接口类型,下面的子项可以全不选,内核中若有其他部分依赖它,会自动选上
-
- Parallel SCSI (SPI) Transport Attributes
- 传统且常见的并行SCSI(Ultra320/160之类)
- FiberChannel Transport Attributes
- 光纤通道
- iSCSI Transport Attributes
- iSCSI是利用TCP/IP网络传送SCSI命令和数据的I/O技术
- SAS Transport Attributes
- 串行SCSI传输属性支持(SAS对于的关系SPI犹如SATA对于ATA)
- SAS Domain Transport Attributes
- 为使用了SAS Domain的驱动程序提供帮助
-
- Compile the SAS Domain Transport Attributes in debug mode
- 仅供调试使用
- SCSI low-level drivers
- 底层SCSI驱动程序,按你实际使用的产品选择
-
- iSCSI Initiator over TCP/IP
- 用于iSCSI在TCP/IP网络上传播的起动程序
- {此处省略的部分按照自己实际使用的控制器进行选择,仅用一个例子解说子项}
- Adaptec AIC79xx U320 support
- 以基于PCI-X的Adaptec Ultra 320 SCSI控制器为例解说子项
-
- Maximum number of TCQ commands per device
- 每个SCSI设备的标记指令队列的最大长度(上限253).上限越高性能越好,但是对于SCSI设备较多的系统来说可能造成内存分配失败.此值还可以通过tag_info内核引导参数指定
- Initial bus reset delay in milli-seconds
- 初始总线reset之后的延时微秒数(默认5000)
- Enable Read Streaming for All Targets
- 对所有的标记队列启用Read Streaming(可以增强效能,但是在一些Adaptec早期的U320产品上有缺陷),此特性还可以通过rd_strm内核引导参数指定
- Compile in Debugging Code
- 仅用于调试
- Debug code enable mask (16383 for all debugging)
- 出错代码的掩码,0表示禁止所有,16383表示打开所有
- Decode registers during diagnostics
- 将出错代码的解释内容编译进去,这样就不需要查看aic7xxx.reg中的出错代码表以确定出错代码的含意了
PCMCIA SCSI adapter support
通过PCMCIA卡与计算机连接的SCSI设备
Serial ATA and Parallel ATA drivers
SATA与PATA设备
- ATA device support
- SATA或PATA接口的硬盘或光驱等设备
-
- AHCI SATA support
- SATA高级主机控制器接口.要使用NCQ功能就必须选中它,另外BIOS中的SATA工作模式亦要选AHCI模式
- Generic ATA support
- 基于新的ATA层的通用ATA控制器驱动,仅在你的芯片组在列表中找不到时才需要
- {此处省略的部分按照自己主板上实际使用的芯片组进行选择}
Old CD-ROM drivers (not SCSI, not IDE)
老旧的CD-ROM驱动,这种CD-ROM既不使用SCSI接口,也不使用IDE接口
Multi-device support (RAID and LVM)
多设备支持(RAID和LVM).RAID和LVM的功能是使多个物理设备组建成一个单独的逻辑磁盘
- RAID support
- 软件RAID(需要使用外部工具),若你有硬件RAID控制器,可以不选
-
- Linear (append) mode
- 追加模式(简单的将一个分区追加在另一个分区之后)
- RAID-0 (striping) mode
- RAID-0(等量分割)模式
- RAID-1 (mirroring) mode
- RAID-1(镜像)模式
- RAID-10 (mirrored striping) mode
- RAID 0+1模式
- RAID-4/RAID-5/RAID-6 mode
- 这些模式比较复杂,一般不用
-
- Support adding drives to a raid-5 array
- RAID-5阵列可以通过添加额外的驱动器进行扩展(restriping),这个选项允许在线进行这样的操作,同时要求mdadm的版本大于2.4.1
- Multipath I/O support
- 多路IO支持是指在服务器和存储设备之间使用冗余的物理路径组件创建"逻辑路径",如果这些组件发生故障并造成路径失败,多路径逻辑将为I/O使用备用路径以使应用程序仍然可以访问其数据
- Faulty test module for MD
- 用于MD(Multi-device)的缺陷测试模块
Device mapper support
Device-mapper是一个底层的卷管理器,不用LVM就别选了
Fusion MPT device support
Fusion MPT设备支持
IEEE 1394 (FireWire) support
IEEE 1394(火线)
I2O device support
I2O(智能IO)设备使用专门的I/O处理器负责中断处理/缓冲存取/数据传输等烦琐任务以减少CPU占用,一般的主板上没这种东西
最近工作项目的板子在加工,就在淘宝买了个AT91RM9200的板子。没想到买回来SDRAM是坏的,于是自己换了。因为不想麻烦,也就没有退货,直接给差评了事。
接下来用开发板作了个WEB服务器,我打算以后把Blog上没有办法添加的东西全部放到那里去。现在还在测试阶段,我住的地方用的是ADSL,不太稳定,请大家见谅。网址: http://cosine.oicp.net。(2009年2月21日追加:此站关闭,上面的文件我搬到SkyDrive上了)
做这个服务器其实很简单,但我已经是不太菜的菜鸟了,就不写那么详细了,可以参考我过去的2410/2440开发文档。下面是作过程提纲:
根文件系统的制作是困扰我很长时间的问题,现在终于有些解决的眉目了。而且现在我用的是udev,实现了1年前的梦想,呵呵。先写到这里,我的机器正在运行Build-root,打字都卡,受不了了。 9月25日 这两天在ARM上跑了一个OpenGL,应该说是OpenGL|ES的软件包,虽然我觉得可能最后我不会使用这个软件包,但是还是记录下来以备忘记。
首先制作交叉编译器,先以root用户登陆,建立交叉编译器安装目录,而且把目录所有者改为你的普通用户
# mkdir /opt/crosstool
# chown /opt/crosstool lxz
# chgrp /opt/crosstool users
然后以普通用户登陆,解压缩和安装
# tar xvzf crosstool-0.43.tar.gz
# cd crosstool-0.43
# ./demo-arm-softfloat.sh
然后解压缩picogl,修改picogl的代码。
首先是picogl的一处bug,在backends/vesafb/tk.c的第一行增加宏
#define _FB_TK_
然后把backends/vesafb/glx_impl.h里面的
struct fb_fix_screeninfo FixedInfo;
struct fb_var_screeninfo VarInfo, OrigVarInfo;
修改为
#ifdef _FB_TK_
struct fb_fix_screeninfo FixedInfo;
struct fb_var_screeninfo VarInfo, OrigVarInfo;
#else
extern struct fb_fix_screeninfo FixedInfo;
extern struct fb_var_screeninfo VarInfo, OrigVarInfo;
#endif
这是因为有好几个文件调用了backends/vesafb/glx_impl.h,如果不这么改,会出现多重定义错误。
然后,为了让你的程序使用picogl更方便些,最好再改个地方include/GL/glx.h
#include GLX_IMPL_HEADER
改为你喜欢的方式,指向backends/vesafb/glx_impl.h
修改backends/vesafb/tk.c中,initialize_fbdev函数有关VarInfo的设置,改为适合你的LCD的。
然后配置
# cd PicoGL
# CC=/opt/crosstool/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux-gnu/bin/arm-softfloat-linux-gnu-gcc ./configure --with-backend=vesafb --host=arm-softfloat-linux-gnu --prefix=/home/lxz/builtPicoGL
说明下,CC=设置交叉编译器的位置,--with-backend=vesafb指定使用FB作为显示设备,host=arm-softfloat-linux-gnu设定交叉编译,--prefix=/home/lxz/builtPicoGL设定编译后库和示例程序安装位置。
然后
# make
# make install
在/home/lxz/builtPicoGL/lib里就有PicoGL的库了,把动态库文件拷贝到arm-linux根文件系统的/lib里面,把/home/lxz/builtPicoGL/bin里的程序拷贝到arm-linux文件系统的任何地方,然后制作和烧写文件系统映像(或者使用NFS),执行,就可以看到结果了。
当你编译一个使用PicoGL库的程序(假设叫做hello.c)时,需要输入
# arm-softfloat-linux-gnu-gcc -c -I /home/lxz/PicoGL/include -I /usr/include hello.c
# arm-softfloat-linux-gnu-gcc -o hello -L /home/lxz/builtPicoGL/lib/libPicoGL.so -L /home/lxz/builtPicoGL/lib/libPicoGLU.so -lm hello.o /home/lxz/builtPicoGL/lib/libPicoGL.a /home/lxz/builtPicoGL/lib/libPicoGLU.a
今天写得比较粗糙,呵呵。 9月18日 今天又取得了一些进展,赶快写下来以免自己忘记。
自从Linux在我的板子上跑起来之后,我一直在想一个问题,怎么调试将来写的程序。其实我在Linux开发方面真得很外行,到了今天才知道GDB到底是干什么用的,呵呵。我相信很多人从Bootloader调试开始一直都使用LED啊,printf这样的方法来调试。我做毕设时,就是在MTDBLOCK里面划出一个USER分区,然后把编译好的程序放入文件系统映像,通过Bootloader用串口下到NAND里,然后mount上调试,实在很花时间。今天,白痴的我终于找到了一条捷径,已经不咳嗽了!
先介绍下DDD和GDB,GDB是一种用于调试Linux下程序的工具,它不仅能调试C/C++,还可以调试Pascal等很多其他语言。我们看个例子:假设有一个程序叫做test.c,要用GDB调试它,首先,编译的时候需要加上产生debug信息选项“-g”,如#arm-linux-gcc test.c -o test -g;然后,由于我们并不是开发本机程序,在目标机(arm)上需要用一个server启动这个含有调试信息的程序,当然,本机和目标机之间得有一定的数据共享方式(如nfs)和一定的通信方式(如以太网或串口);最后,在本机上启动一个GDB客户端,就可以登陆到目标机的server上调试程序了。GDB的原理网上也有很多文章说,可以搜索下,但是我是初学者,就不去看那些内容了。为了让大家更加明确GDB和DDD的区别,我们先看一个GDB的调试过程:
我通过以太网调试,本机IP地址192.168.2.31,目标机(arm开发板IP地址192.168.2.223),本机通过nfs共享开发目录lgraphics。
首先本机上编译:
lxz@lxzlinux:~/lgraphics> arm-linux-gcc lgraphics.c -o lg -g
切换到目标机:
[root@(none) lgraphics]# gdbserver 192.168.2.31:2345 lg Process lg created; pid = 402 Listening on port 2345
切换到本机: lxz@lxzlinux:~/lgraphics> arm-linux-gdb lg GNU gdb 6.6 Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-linux"... (gdb) target remote 192.168.2.223:2345 lg Remote debugging using 192.168.2.223:2345 lg 0x40001290 in _start () from /lib/ld-linux.so.2
此时,目标机上也会出现:
Remote debugging from host 192.168.2.31
在本机上输入:
(gdb) b main (设置断点到main函数) Breakpoint 1 at 0x9c00: file lgraphics.c, line 442. (gdb) cont (开始执行) Continuing.
Breakpoint 1, main () at lgraphics.c:442 (遇到断点,并显示断点程序行) 442 int i, j, b = 0; (gdb) step (单步执行) 445 linitgraph("/dev/fb0"); (显示目前程序行)
好了,看到这里,差不多就明白GDB是干什么的、怎么用了吧。我相信你会和我一样对GDB界面的不友好表示愤慨,想想Windows下的开发工具,哪一种调试的时候还是文本界面的。幸运的是,有一些勤快的人,帮我们写了很多GDB的图形化前端,我们更本不用像上面这样使用GDB。
开始说DDD。DDD是一种GDB的图形化前端,就是一种用图形界面帮你输入繁琐的GDB调试指令工具。当然,也有很多文章说DDD多么不足,用Insight来取代它之类的。我的Suse里恰好就有DDD,我也不管那么多了,先用了。看看用DDD的时候怎么调试:
一样本机上编译:
lxz@lxzlinux:~/lgraphics> arm-linux-gcc lgraphics.c -o lg -g
切换到目标机:
[root@(none) lgraphics]# gdbserver 192.168.2.31:2345 lg Process lg created; pid = 402 Listening on port 2345
切换到本机: lxz@lxzlinux:~/lgraphics> ddd -debugger arm-linux-gdb lg
然后就会启动DDD的图形界面,在窗口下方有一个文本输入框,这里就是ddd的基础gdb的所在,在这里输入target remote 192.168.2.223:2345 lg,提示信息和我们用GDB时候是一样的。不同的是,除了这句连接目标机的指令,其他指令都不用输入了,可以在图形化界面里找到,这我就不说了。另外,连接目标机的指令也可以用在DDD中设置,不用输入,可以查找其他介绍DDD使用的文章。下面是DDD的图形界面,工具栏下面的是watch,代码可以设置断点(红色点),可以看到单步位置(绿色箭头),右边是执行控制工具条,最下面是GDB的输入和输出显示。
看到这里,想我一样的菜鸟们一定发现了,原来Linux程序可以这么好调啊,简直和CE没有什么差别了,呵呵。下面介绍为了使用GDB+DDD所要做的东西。我不是从零开始建立的,具体的包依存关系我也不明白,只好假设你在安装Linux的时候已经安装了像GCC,DDD之类的工具。GDB的源代码包gdb-6.6.tar.bz2可以从 ftp://gcc.gnu.org上下载到,还有一个要求是你已经安装了交叉编译器arm-linux-gcc。
下载下来后:
# tar xvjf gdb-6.6.tar.bz2
# mkdir gdbbuild
# cd gdbbuild
# ../gdb-6.6/configure --target=arm-linux --prefix=/home/lxz/lxzgdb
这里,--prefix参数是需要安装的目录,然后
# make
# make install
这样,arm-linux-gdb这个工具就在/home/lxz/lxzgdb/bin里头了,你可以把这个路径添加到PATH里面去
接下来建立gdbserver,在gdbbuild的上一级目录下
# mkdir gdbserverbuild
# cd gdbserverbuild
# CC=arm-linux-gcc ../gdb-6.6/gdb/gdbserver/configure --host=arm-linux --prefix=/home/lxz/lxzgdbserver
一样,--prefix参数是需要安装的目录,然后
# make
# make install
有的文章里说,要去除arm-linux-strip的调试信息
# cd /home/lxz/lxzgdbserver/bin
# arm-linux-strip gdbserver
把这个gdbserver复制到你的开发板上,就OK了。
今天就写到这里。 9月13日 又是好久没有更新了,同样记录下这段时间干的事情。
来到公司报道之后我就去了工厂,呆了一个多月,熟悉公司各种产品的生产过程。当然,就是和生产线上的小MM们聊聊天,哈哈,开玩笑了。这期间我的导师给我了个任务——一个UI的低成本实现。这个UI必须具有LCD显示、USB主机、网络等功能,要求就是低成本低成本再低成本;很自然选型选完之后就又变成搞ARM了。买了开发板,硬件就没有什么好说的了。任务的重点落在了软件上,刚开始我和导师达成的意见是代码裸奔(省去授权费用),或者穿个自己写的小OS。于是我花了2个星期的时间写了0.8(写了任务切换,其他没有最后写完)个类似uCOS功能的小OS,发现这种东西跑在ARM920T上实在发挥不出920T的功能,于是我又花了2个星期写了存储管理,打算加入MMU;但是写完发现就算系统能工作,我怎么调试应用程序是个大问题,因为用了MMU,用户进程就不能和内核一起玩了。经过和导师的商量,我再次回到了Linux;目前的打算是使用免费的内核,自己写个类似TC的图形库,或者使用Microwindows + FLTK之类的不要钱的东西。很浪费时间啊,花了4个星期才发现原来自己写系统真的是非常困难的。但是这4个星期也没有白花,有些附属产品,例如自己写的不需要stdlib库的malloc。其实我是第二次写这个东西了,第一次的不太成熟,用了几次就发现局限性了。现在写的这个是我啃了几天操作系统原理写的,应该相对好用,以后有空我会贴出代码来。
然后就是我做过的Linux开发过程了,其实说起来,这次开发我发现自己Linux真的什么都不懂。过去偷懒没有花时间好好看看Linux内核,现在造成很多麻烦,今天这些问题,熟悉内核的人只需要1分钟就能搞定了,我花了1天多。写下这个笔记,以便以后查阅使用。
第一个问题:启动Linux的时候LCD会全屏花屏大约0.5秒,然后左上角出现一块不明花斑。
这个问题相对简单。因为我在Bootloader里面打开了液晶显示,缓冲区映射在某个地址上,当内核初始化MMU的时候,LCD控制寄存器里缓冲区的位置信息就不对了,或者是Bootloader使用的缓冲区被内核的数据或代码覆盖,导致在内核初始化LCD之前,LCD花屏。
那个不明花斑其实是Linux的可爱小企鹅图片,但是可能因为缓冲区像素位宽和格式、LCD调色板设置等问题显示不出来。
花屏解决方法:在Bootloader加载系统之前关掉LCD控制器或者关掉LCD的背光,这样做比较简单。复杂的,就得改MMU映射部分代码,在修改了MMU映射之后,立即修改LCD缓冲的位置。反正我就关掉LCD控制器了,因为内核很快就会初始化LCD,Windows启动都黑屏呢,我们黑那么2秒钟也没有什么大不了的。
花斑解决方法:相信如果做产品的话,不需要显示什么企鹅给用户看,所以可以在内核选项里将这个企鹅logo关掉。具体位置在Device Drivers>Graphics support>Logo configuration,对应的宏相信在.config里面很容易找到。如果非要显示这个企鹅,那么可以在/drivers/video/console/fbcon.c里面找找,我也不知道怎么弄。
第二个问题:Linux启动之后,只要一段时间不动键盘(开发板上用IO扩展出来的键盘),LCD就会自动关闭(黑屏、显示慢慢消失之类),只要按下键盘就能恢复。
这个问题让我花了一天多的时间。其实如果是手持设备,这样也没有什么。但是我们公司的产品是要一直显示东西的,必须解决这个问题。我看了很多论坛,有不少人也遇到了这个问题,但是我刚才是搜索的时候,关键词不对,总找不到正确的答案。如果你遇到了同样的问题,而且不想看我的三脚猫分析,那么就在百度上搜索“blankinterval”、“setterm -blank 0”之类的,马上你就能找到简单的解决方案。
这个问题很容易让人想到屏幕保护和电源管理。的确,这是一种电源管理。但是,你却无法从Linux内核选项的电源管理中解决这个问题。我们一步步来。
首先,我测量到LCD的PCLK时钟消失了,这意味着内核把LCD控制器关掉了。于是,从LCD驱动程序着手。我用的是S3C2440,这是2410的升级版,但是LCD控制器是一样的,在我拿到的开发板厂商给我做好驱动的内核里,驱动的位置在/drivers/video/s3c2410fb.c。为什么后面有个fb呢?这是Framebuffer的缩写,百度下你能找到很多关于它的解释。Framebuffer是所有Linux下GUI程序对硬件操作的设备接口,位于/dev中,一般为fb0。在s3c2410fb.c中可以找到一个类似s3c2410_disable_controller()这样名称的函数,我的驱动里叫pxafb_disable_controller(),可以看出这个驱动是从pxa处理器改的,当然厂家不一样名字也叫得不一样。里面有一句类似这样写的__raw_writel(fbi->reg.lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);,把这句话删掉LCD就不会关掉了。这是第一个层次,我也看到有人是这样做的。但是,这有问题,按键盘恢复后,原本显示在屏幕上的东西如果你不重画会消失,就算你重画了,也会看到屏幕的某些部分先黑了下,然后恢复了。当然如果你可以接受,那么就这样吧。
然后,可以很自然的想到是谁调用了这个函数,从源头把这个问题消除掉。但是情况却不是这样的。我搜索这个函数名,找到了一个set_ctrlr_state()的函数调用了pxafb_disable_controller(),搜索set_ctrlr_state(),发现有个pxafb_task()调用了set_ctrlr_state(),但是到了pxafb_task()就没有办法再往上找了,因为这是提供给内核的一个任务,以指针传递函数入口。我对内核了解太不够了,花了很多时间看了很多论坛上的文章,机缘巧合之下,我找到了/drivers/char/vt.c这个文件。vt.c我感觉应该是2.4内核的console.c和vt.c的结合体,应为它集成了console基本上所有功能函数,就ioctl在vt_ioctl.c这个文件里。这个文件的主要作用是负责管理控制台,如控制台的模式(图形、字符)、向控制台输出等等。其中能找到一些如do_blank_screen(),blank_screen_t()这样的函数,就是这些函数关闭了LCD控制器,修改任意一个都可以起作用。网上的一个解决方案是把blank_screen_t()变成空函数,但是我没有这样试过,我觉得已经来到了问题的根源附近,应该能从根本上解决。
我们先看下屏幕关闭问题的真正起因,看这个控制台初始化函数
static int __init con_init(void) { const char *display_desc = NULL; struct vc_data *vc; unsigned int currcons = 0;
acquire_console_sem();
if (conswitchp) display_desc = conswitchp->con_startup(); if (!display_desc) { fg_console = 0; release_console_sem(); return 0; }
init_timer(&console_timer); console_timer.function = blank_screen_t; if (blankinterval) { blank_state = blank_normal_wait; mod_timer(&console_timer, jiffies + blankinterval); }
// 这是对控制台定时器的初始化,定时器事件函数被连接到了blank_screen_t()
/* * kmalloc is not running yet - we use the bootmem allocator. */ for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data)); visual_init(vc, currcons, 1); vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size); vc->vc_kmalloced = 0; vc_init(vc, vc->vc_rows, vc->vc_cols, currcons || !vc->vc_sw->con_save_screen); } currcons = fg_console = 0; master_display_fg = vc = vc_cons[currcons].d; set_origin(vc); save_screen(vc); gotoxy(vc, vc->vc_x, vc->vc_y); csi_J(vc, 0); update_screen(vc); printk("Console: %s %s %dx%d", vc->vc_can_do_color ? "colour" : "mono", display_desc, vc->vc_cols, vc->vc_rows); printable = 1; printk("\n");
release_console_sem();
#ifdef CONFIG_VT_CONSOLE register_console(&vt_console_driver); #endif return 0; }
其中引用了一个叫blankinterval的全局变量和一个console_time,我不知道内核的定时器是具体是怎么工作,但是这样的代码已经很明显了。这个定时器和电源管理宏PM_CONFIG没有任何关系,它是控制台的一部分。再看下blank_screen_t():
static void blank_screen_t(unsigned long dummy) { blank_timer_expired = 1; schedule_work(&console_work); }
可以发现vt.c开头的宏,static DECLARE_WORK(console_work, console_callback, NULL);,找到了console_callback()这个函数:
static void console_callback(void *ignored) { acquire_console_sem();
if (want_console >= 0) { if (want_console != fg_console && vc_cons_allocated(want_console)) { hide_cursor(vc_cons[fg_console].d); change_console(vc_cons[want_console].d); /* we only changed when the console had already been allocated - a new console is not created in an interrupt routine */ } want_console = -1; } if (do_poke_blanked_console) { /* do not unblank for a LED change */ do_poke_blanked_console = 0; poke_blanked_console(); } if (scrollback_delta) { struct vc_data *vc = vc_cons[fg_console].d; clear_selection(); if (vc->vc_mode == KD_TEXT) vc->vc_sw->con_scrolldelta(vc, scrollback_delta); scrollback_delta = 0; } if (blank_timer_expired) { do_blank_screen(0); blank_timer_expired = 0; }
release_console_sem(); }
再看do_blank_screen(),随着struct vc_data中的与fops类似指针跟踪下去,就可以找到驱动里面的相应代码了。写出来太麻烦,让我偷懒把。
小总结下,其实在控制台内部就有一个定时器,它负责在一定时间之后将显示关闭,而无视是否打开了电源管理功能。那这和Framebuffer有什么关系呢?我从一个很弱智的角度解释,内核刚启动的时候有这样一句输出:
Console: colour dummy device 80x30
在初始化LCD控制器(Framebuffer)之后,有这样一句输出:
Console: switching to colour frame buffer device 80x30
我就理解:这时候,内核把控制台(也不知道是console还是tty)切换到了Framebuffer上,大虾们赶快跳出来批判我吧,呵呵。
回到正题,从代码可以发现,根本的解决之道是让blankinterval = 0,blank_state就不会是blank_off之外的值,也就不会关闭屏幕了。
但是问题到这里还是没有完全解决,如果用户程序希望改变blankinterval来实现屏保(当然在我的系统上用不着);另外,一些程序改变了blankinterval,程序退出之后,屏幕在一段时间之后还是会关闭的。怎么才能在用户程序那头解决这个问题呢,这又耗费了我很多时间。
我在追查代码的过程中走了个弯路,认为修改控制台的模式可以不让黑屏现象出现,但是后来发现,这样可能会使控制台没有办法画图,不知道对不对。
忽略弯路,直接正解。vt.c中不是有很多操作控制台的函数么?看看是谁修改了blankinterval。于是搜索blankinterval,发现setterm_command()修改了它,然后搜索setterm_command,找到了do_con_trol()函数,搜索do_con_trol,找到了do_con_write()函数,搜索do_con_write,终于最终BOSS现身了:con_write()函数。为什么说它是最终BOSS呢?看看这段:
static struct tty_operations con_ops = { .open = con_open, .close = con_close, .write = con_write, .write_room = con_write_room, .put_char = con_put_char, .flush_chars = con_flush_chars, .chars_in_buffer = con_chars_in_buffer, .ioctl = vt_ioctl, .stop = con_stop, .start = con_start, .throttle = con_throttle, .unthrottle = con_unthrottle, };
熟悉fops的话你就能看出来了,这是对tty设备的文件操作函数的表。也就是说,在用户程序里,通过open函数打开/dev/tty,然后再用write函数就可以修改blankinterval了。原理是找到了,实践上有很大困难,那么多重函数调用,再看看do_con_trol()里面的switch语句,正常人都要发晕。好在伟大的百度为我们提供了很多信息:在命令行下,可以使用setterm -blank 0指令来设置blankinterval。哈哈,救星来了,赶快看看setterm的源代码。setterm属于util-linux包,搜索一下很容易找到。其中的perform_sequence()函数里有这样一段:
/* -blank [0-60]. */ if (opt_blank && vcterm) printf("\033[9;%d]", opt_bl_min);
真得很神奇啊,用个printf就可以在用户程序里解决这个问题,本来我是打算只说用printf解决的,看到原理我想会更舒服一些;况且,在我的系统上用printf是不行的。
但是!问题还没有完,往往在我们的系统中,LCD的虚拟控制台和控制台TTY不是同一个设备,也就是说,如果在程序里单纯的printf是不行的!这样只能修改你正在使用的TTY的blankinterval,而你用的却是文本方式的设备,不存在黑屏问题。
于是,就需要仔细比较/dev/console、/dev/tty、/dev/ttyn的设备号,在我的系统里,用户程序里/dev/console和/dev/tty都是5,说明他们是一个东西,/dev/ttyn是4,这才是FB上的虚拟控制台。但是/dev/ttyn不是正在使用的TTY,那么怎么printf呢?只好用write函数来解决了。
写这样一段代码:
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
void some_function()
{
int f;
f = open("/dev/tty0", O_RDWR);
write(f, "\033[9;0]", 8);
close(f);
}
问题终于解决了。
总结下,第二个问题有很多种解决方法:
1.修改LCD驱动,把关闭LCD控制器的函数变为空(不推荐)
2.修改vt.c中的blank_screen_t()函数,让其为空(在系统不需要使用关闭显示功能时推荐)
3.修改vt.c中的blankinterval,让其为0(系统可能需要使用关闭显示功能,而且希望系统上电后正常状态下不会关闭显示时推荐)
4.修改用户程序,加入设置blankinterval的代码(推荐)
今天就写到这里,继续干活了。 5月30日 写这些东西还真是花时间啊,继续昨天的内容。
我写驱动的时候总希望能找到一个样例参考一下,可惜网上的例子基本找不到。还好友善之臂的文档里有些例子,但是说的很不详细,要是直接输入会有很多的编译错误。我的这个例子是一个控制LED的例子,用Linux就控制LED,当然是相当的弱智的哈哈。我用的是S3C2410,LED连接在GPB7~10上,灌电流方式驱动,IO配置寄存器GPBCON的物理地址0x56000010,IO数据寄存器GPBDAT的物理地址0x56000014。程序中的几个关键点,在我昨天的BLOG中有叙述。
首先编写一个叫做leds_test.c的文件,内容如下:
#include <linux/config.h> #include <linux/fs.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/init.h>
//Please configure your kernel first to use the following headers, because the directory "asm" is a short cut to your arch's "asm" directory.
//So do the headers in the "hardware" sub directory. #include <asm/io.h> //This header is for ioremap(), iounmap(). #include <asm/uaccess.h> //This header is for get_user(), put_user().
#define NAME "led_test"
MODULE_AUTHOR("Lu Xianzi < cosine@126.com>"); //This line and the following 4 lines can be omitted. MODULE_DESCRIPTION("LED Test Driver"); MODULE_LICENSE("GPL");
module_param(major, int, 0); MODULE_PARM_DESC(major, "Major device number");
static int major = 231; //Define device major unsigned long * pREG; //Definition of register base.
static ssize_t led_test_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { char buf[256]; size_t i;
for (i = 0; i < len && i < 254; i++) if (get_user(buf[i], data + i)) return -EFAULT; buf[i] = '\0'; printk("LED Test - write: user_data %s\n", buf); return (len < 255 ? len : 255); }
static ssize_t led_test_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { char rbuf[4]; size_t i; long tmp; tmp = * (volatile unsigned long *)(pREG + 1); rbuf[0] = tmp % 256; rbuf[1] = (tmp >> 8) % 256; rbuf[2] = (tmp >> 16) % 256; rbuf[3] = (tmp >> 24) % 256; if (len > 4) return 0; for (i = 0; i < len && i < 4; i++) if (put_user(rbuf[i], buf + i)) return -EFAULT; printk("LED Test - read\n"); return (len < 4 ? len : 4); }
static int led_test_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long tmp;
printk("LED Test - ioctl: param %u %lu\n", cmd, arg); switch (cmd) { case 0: case 1: if (arg > 3) return -EINVAL; if (!cmd) * (volatile unsigned long *)(pREG + 1) |= (0x80 << arg); else * (volatile unsigned long *)(pREG + 1) &= ~(0x80 << arg); tmp = * (volatile unsigned long *)pREG; printk("GPBCON = 0x%lx\n", tmp); tmp = * (volatile unsigned long *)(pREG + 1); printk("GPBDAT = 0x%lx\n", tmp); break; default: return -EINVAL; } return 1; }
static int led_test_open(struct inode *inode, struct file *file) { unsigned m = iminor(inode); if (m > 63) return -EINVAL; printk("LED Test driver opened!\n"); return nonseekable_open(inode, file); }
static int led_test_release(struct inode *inode, struct file *file) { printk("LED Test driver released!\n"); return 0; }
static struct file_operations led_test_fops = { .owner = THIS_MODULE, .ioctl = led_test_ioctl, .write = led_test_write, .read = led_test_read, .open = led_test_open, .release = led_test_release, };
static int __init led_test_init(void) { int ret; unsigned long tmp; printk("LXZ LED Test Driver.\n");
ret = register_chrdev(major, NAME, &led_test_fops); if (ret < 0) { printk("Unable to register character device!\n"); return ret; } pREG = ioremap(0x56000010, 0x20); printk("Virtual addr base = 0x%lx\n", (unsigned long)pREG); tmp = * (volatile unsigned long *)pREG; printk("GPBCON = 0x%lx\n", tmp); tmp = * (volatile unsigned long *)(pREG + 1); printk("GPBDAT = 0x%lx\n", tmp); printk("Seting LED Test Driver...\n"); * (volatile unsigned long *)pREG = 0x155555; * (volatile unsigned long *)(pREG + 1) = 0xfff; tmp = * (volatile unsigned long *)pREG; printk("GPBCON = 0x%lx\n", tmp); tmp = * (volatile unsigned long *)(pREG + 1); printk("GPBDAT = 0x%lx\n", tmp); printk("LED Test Driver initiated.\n"); return 0; }
static void __exit led_test_cleanup(void) { int ret; iounmap(pREG); ret = unregister_chrdev(major, NAME); if (ret < 0) printk("Unable to register character device!\n");
else printk("LED Test Driver unloaded!"); }
module_init(led_test_init); module_exit(led_test_cleanup);
在驱动程序的目录下建立一个名为“Makefile”的文件,其内容只有一行:
obj-m := leds_test.o
编译之,我的linux内核存在/home/lxz/linux-2.6.11.7,所以编译命令为
make -k -C /home/lxz/linux-2.6.11.7 SUBDIRS=$PWD modules
编译后生成几个文件,其中leds_test.ko是我们需要的驱动模块。
然后在另外一个目录中编写一个叫做leds.c的文件,其内容如下
#include <stdio.h> #include <fcntl.h> int main(int argc, char **argv) { int fd; int on, led_no; char buf[256] = {"1234567890"}; unsigned long tmp; if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2], "%d", &on) != 1 || on < 0 || on > 1 || led_no < 0 || led_no >3) { fprintf(stderr, "Usage: leds led_no 0|1\n"); exit(1); } fd = open("/dev/leds", O_RDWR); if (fd < 0) { perror("open device leds"); exit(1); } ioctl(fd, on, led_no); write(fd, buf, 10); read(fd, buf, 4); tmp = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); printf("User program read: GPBDAT = 0x%lx\n", tmp); close(fd); return 0;
} 编译之,输入
arm-linux-gcc -o leds leds.c
然后把生成的leds_test.ko和leds这2个文件拷贝到你的文件系统中,如/home下,启动Linux。之后的过程如下:
/ # cd /home /home # insmod leds_test.ko Lxz LED Test Driver. Virtual addr base = 0xc485e010 GPBCON = 0x44555 GPBDAT = 0x540 Seting LED Test Driver... GPBCON = 0x155555 GPBDAT = 0x7ff LED Test Driver initiated. /home # mknod /dev/leds c 231 0 /home # ./leds 0 1 LED Test driver opened! LED Test - ioctl: param 1 0 GPBCON = 0x155555 GPBDAT = 0x77f LED Test - write: user_data 1234567890 LED Test - read User proLED Test driver released! gram read: GPBDAT = 0x77f /home #
这里有个非常有趣的事情,你会发现内核的printk函数比客户程序的printf函数打印时出现一些混乱,我想应该是因为Linux不是一个实时系统,内核和用户程序分时执行的结果。
如果要卸载驱动模块,如下:
/ # rmmod leds_test
LED Test Driver unloaded!
/ #
5月29日
Linux下的设备驱动程序被组织为一组完成不同任务的函数的集合,通过这些函数使得Windows的设备操作犹如文件一般。在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作,如open ()、close ()、read ()、write () 等。 Linux主要将设备分为二类:字符设备和块设备。字符设备是指设备发送和接收数据以字符的形式进行;而块设备则以整个数据缓冲区的形式进行。字符设备的驱动相对比较简单。 下面我们来假设一个非常简单的虚拟字符设备:这个设备中只有一个4个字节的全局变量int global_var,而这个设备的名字叫做"gobalvar"。对"gobalvar"设备的读写等操作即是对其中全局变量global_var的操作。 驱动程序是内核的一部分,因此我们需要给其添加模块初始化函数,该函数用来完成对所控设备的初始化工作,并调用register_chrdev() 函数注册字符设备:
static int __init gobalvar_init(void) { if (register_chrdev(MAJOR_NUM, " gobalvar ", &gobalvar_fops)) { //…注册失败 } else { //…注册成功 } } | 其中,register_chrdev函数中的参数MAJOR_NUM为主设备号,"gobalvar"为设备名,gobalvar_fops为包含基本函数入口点的结构体,类型为file_operations。当gobalvar模块被加载时,gobalvar_init被执行,它将调用内核函数register_chrdev,把驱动程序的基本入口点指针存放在内核的字符设备地址表中,在用户进程对该设备执行系统调用时提供入口地址。 与模块初始化函数对应的就是模块卸载函数,需要调用register_chrdev()的"反函数" unregister_chrdev():
static void __exit gobalvar_exit(void) { if (unregister_chrdev(MAJOR_NUM, " gobalvar ")) { //…卸载失败 } else { //…卸载成功 } } | 随着内核不断增加新的功能,file_operations结构体已逐渐变得越来越大,但是大多数的驱动程序只是利用了其中的一部分。对于字符设备来说,要提供的主要入口有:open ()、release ()、read ()、write ()、ioctl ()、llseek()、poll()等。 open()函数 对设备特殊文件进行open()系统调用时,将调用驱动程序的open () 函数:
| int (*open)(struct inode * ,struct file *); | 其中参数inode为设备特殊文件的inode (索引结点) 结构的指针,参数file是指向这一设备的文件结构的指针。open()的主要任务是确定硬件处在就绪状态、验证次设备号的合法性(次设备号可以用MINOR(inode-> i - rdev) 取得)、控制使用设备的进程数、根据执行情况返回状态码(0表示成功,负数表示存在错误) 等; release()函数 当最后一个打开设备的用户进程执行close ()系统调用时,内核将调用驱动程序的release () 函数:
| void (*release) (struct inode * ,struct file *) ; | release 函数的主要任务是清理未结束的输入/输出操作、释放资源、用户自定义排他标志的复位等。 read()函数 当对设备特殊文件进行read() 系统调用时,将调用驱动程序read() 函数:
| ssize_t (*read) (struct file *, char *, size_t, loff_t *); | 用来从设备中读取数据。当该函数指针被赋为NULL 值时,将导致read 系统调用出错并返回-EINVAL("Invalid argument,非法参数")。函数返回非负值表示成功读取的字节数(返回值为"signed size"数据类型,通常就是目标平台上的固有整数类型)。 globalvar_read函数中内核空间与用户空间的内存交互需要借助第2节所介绍的函数:
static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off) { … copy_to_user(buf, &global_var, sizeof(int)); … } | write( ) 函数 当设备特殊文件进行write () 系统调用时,将调用驱动程序的write () 函数:
| ssize_t (*write) (struct file *, const char *, size_t, loff_t *); | 向设备发送数据。如果没有这个函数,write 系统调用会向调用程序返回一个-EINVAL。如果返回值非负,则表示成功写入的字节数。 globalvar_write函数中内核空间与用户空间的内存交互需要借助第2节所介绍的函数:
static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off) { … copy_from_user(&global_var, buf, sizeof(int)); … } | ioctl() 函数 该函数是特殊的控制函数,可以通过它向设备传递控制信息或从设备取得状态信息,函数原型为:
| int (*ioctl) (struct inode * ,struct file * ,unsigned int ,unsigned long); | unsigned int参数为设备驱动程序要执行的命令的代码,由用户自定义,unsigned long参数为相应的命令提供参数,类型可以是整型、指针等。如果设备不提供ioctl 入口点,则对于任何内核未预先定义的请求,ioctl 系统调用将返回错误(-ENOTTY,"No such ioctl fordevice,该设备无此ioctl 命令")。如果该设备方法返回一个非负值,那么该值会被返回给调用程序以表示调用成功。 llseek()函数 该函数用来修改文件的当前读写位置,并将新位置作为(正的)返回值返回,原型为:
| loff_t (*llseek) (struct file *, loff_t, int); | poll()函数 poll 方法是poll 和select 这两个系统调用的后端实现,用来查询设备是否可读或可写,或是否处于某种特殊状态,原型为:
| unsigned int (*poll) (struct file *, struct poll_table_struct *); |
设备"gobalvar"的驱动程序的这些函数应分别命名为gobalvar_open、gobalvar_ release、gobalvar_read、gobalvar_write、gobalvar_ioctl,因此设备"gobalvar"的基本入口点结构变量gobalvar_fops 赋值如下:
struct file_operations gobalvar_fops = { read: gobalvar_read, write: gobalvar_write, }; | 上述代码中对gobalvar_fops的初始化方法并不是标准C所支持的,属于GNU扩展语法。 完整的globalvar.c文件源代码如下:
#include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <asm/uaccess.h> MODULE_LICENSE("GPL");
#define MAJOR_NUM 254 //主设备号
static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*); static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);
//初始化字符设备驱动的file_operations结构体 struct file_operations globalvar_fops = { read: globalvar_read, write: globalvar_write, }; static int global_var = 0; //"globalvar"设备的全局变量
static int __init globalvar_init(void) { int ret;
//注册设备驱动 ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops); if (ret) { printk("globalvar register failure"); } else { printk("globalvar register success"); } return ret; }
static void __exit globalvar_exit(void) { int ret;
//注销设备驱动 ret = unregister_chrdev(MAJOR_NUM, "globalvar"); if (ret) { printk("globalvar unregister failure"); } else { printk("globalvar unregister success"); } }
static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off) { //将global_var从内核空间复制到用户空间 if (copy_to_user(buf, &global_var, sizeof(int))) { return - EFAULT; } return sizeof(int); }
static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off) { //将用户空间的数据复制到内核空间的global_var if (copy_from_user(&global_var, buf, sizeof(int))) { return - EFAULT; } return sizeof(int); }
module_init(globalvar_init); module_exit(globalvar_exit); | 运行:
| gcc -D__KERNEL__ -DMODULE -DLINUX -I /usr/local/src/linux2.4/include -c -o globalvar.o globalvar.c | 编译代码,运行:
加载globalvar模块,再运行:
发现其中多出了"254 globalvar"一行,如下图:
接着我们可以运行:
| mknod /dev/globalvar c 254 0 | 创建设备节点,用户进程通过/dev/globalvar这个路径就可以访问到这个全局变量虚拟设备了。我们写一个用户态的程序globalvartest.c来验证上述设备:
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <fcntl.h> main() { int fd, num; //打开"/dev/globalvar" fd = open("/dev/globalvar", O_RDWR, S_IRUSR | S_IWUSR); if (fd != -1 ) { //初次读globalvar read(fd, &num, sizeof(int)); printf("The globalvar is %d\n", num);
//写globalvar printf("Please input the num written to globalvar\n"); scanf("%d", &num); write(fd, &num, sizeof(int));
//再次读globalvar read(fd, &num, sizeof(int)); printf("The globalvar is %d\n", num);
//关闭"/dev/globalvar" close(fd); } else { printf("Device open failure\n"); } } | 编译上述文件:
| gcc -o globalvartest.o globalvartest.c | 运行
可以发现"globalvar"设备可以正确的读写。 做人要厚道,转载请注明。有人摘录我BLOG中的话当作自己说的。我认为只要能找出出处的摘录,都会注明来源,以方便阅读的人做进一步的搜索。
花了4天的时间基本整明白了怎么写一个字符设备的驱动,呵呵,我也不知道原理,紧紧是从网上找到了很多文章,加以综合,搞出一个不明原理的HOWTO,趁我的大脑还没有变成浆糊,把这些写出来。内核移植和文件系统构建部分先暂缓。
向大家推荐一个网站,http://www.linuxforum.net/index.php,上面的版主很热心,而且之前的文章很多,可以给大家很大的帮助。
什么是字符设备?我也搞不清楚,哈哈,快要毕业了,速成的结果。目前我弄明白的是:字符设备是以字节为单位来读写的,与字符设备相对应的,块设备是以块为单位来读写的。例如我在总线上扩展的FPGA,它的控制字映射到总线上,每次读写一个字(16位)。
在Linux下和无操作系统情况下,对总线上地址的访问是不同的,Linux提供的内存虚拟内存机制使用户程序无法直接接触到物理内存——这就需要驱动程序这个桥梁。我们先从用户的角度出发,看看怎么使用设备。做人要厚道,下面这段文字来自友善之臂的文档(这个文档可以在他们的主页上下到,http://www.arm9.com.cn/product_more.asp?id=1185)
|
Linux操作系统将所有的设备(而不仅是存储器里的文件)全部都看成文件,都纳入文件系统的范畴,都通过文件的操作界面进行操作。这意味着:
每一个设备都至少由文件系统的一个文件代表,因而都有一个“文件名”。每个这样的“设备文件”都唯一地确定了系统中地一项设备。应用程序通过设备地文件寻找访问具体地设备,而设备则象普通文件一样受到文件系统访问权限控制机制地保护。
应用程序通常可以通过系统调用open()“打开”这个设备文件,建立起与目标设备的连接。代表着该设备的文件节点中记载着建立这种连接所需的信息。对于执行该应用程序的进程而言,建立起的连接就表现为一个已经打开的文件。
打开了代表着目标设备的文件,即建立起与设备的连接后,就可以通过read()、write()、ioctl()等常规的文件操作对目标设备进行操作。
|
目前我的理解是驱动程序所要做的,是将硬件设备(通常是物理地址)与文件操作相关联。当然,我觉得这句话不太全面,以后我学明白原理以后再回来改,FIXME。
驱动程序需要完成的工作有:初始化设备、管理设备、提供文件读写操作的接口、处理设备出现的错误等。
那么驱动程序怎么才能被内核使用呢?或者说怎么样才能把驱动程序加入我的系统中呢?有两种方式:一是把驱动程序直接编译进内核;二是使用模块加载的方式。我采用的是第二种。第一种的细节问题我没有怎么研究,大致上就是写好驱动程序之后,放到内核代码的目录里,修改Makefile文件,与内核一同编译。可以参考《Linux 字符设备驱动程序的设计》,潘俊强、刘莉,杭州应用工程技术学院学报,第12卷第4期,2000年12月。我在百度上搜到这个文章而且下载的,应该还能搜到。 着重介绍第二种方式,因为这可以给调试带来很大的方便,我相信大家的机器不会快到编译一遍有几万个文件的内核和编译一个小文件速度差不多的程度,另外就算你有网络下载内核的开发板,600~800k和十多k还是有差距的,呵呵。
先说下我调试模块的方法,在MTD中留个USER分区,然后用VIVI将USER分区的映像用串口下载到NAND Flash,启动内核,挂载USER分区。如果把驱动程序模块和使用驱动程序模块的测试程序都放在根文件系统里,每次都下载实在比较费事。当然,如果你的板子已经能在Linux下访问网络,那太好了,nfs也好,tftp也好,速度就更快了。
下面开始Step by Step:
- 配置内核,到你的内核的目录下,make menuconfig,第三项“Loadable module support”,选上“Enable loadable module support”,其他的随便,我就多选了个“Module unloading”。然后,重新编译内核。
- 配置Shell,我用的是Busybox 1.00,到你的Busybox目录下,make menuconfig,找到“Linux Module Utilties”,选上“insmod”、“Support version 2.6.x Linux kernels”、“rmmod”、“Support taintd module checking with new kernels”,这里很奇怪,选上“lsmod”和“modprobe”我的Busybox就不工作了,我觉得是和我用的lib有关。因为我还没有成功编译libs,所以就拉倒,反正insmod,rmmod也够用了。解释下,insmod是挂载模块的命令,rmmod是卸载命令。然后重新编译Busybox,重新构建文件系统映像,我用的是cramfs;哈哈,还没有移植yaffs,为了毕业先将就了。
- 烧写新的内核和文件系统,说下,最好备份一个可用的内核和Shell的配置文件,相信来看这篇文章的都不是高手,弄不明白那些选项和编译器、库以及各种头文件的关联关系,也许你修改一下再编译,内核或者Shell就不好使了。
- 编写内核驱动程序。这个部分请看我下一篇文章,我也是看了那位高手的HOWTO才会明白其中细节的。
- 编写使用驱动程序的测试程序。这是用来调试编写的驱动是不是真的好使,这个部分也请看我后面的文章。
在编写内核驱动程序的时候,需要注意的有这几点(建议你看完下一篇文章之后再回来看这下面的东西):
- Linux 2.6和2.4内核的字符设备驱动的标准模版不同,网上能够搜到的多半是2.4的东西,需要修改。
2.4内核的驱动模版是 #define MODULE #include <linux/module.h> #include <linux/config.h> static int __init init_module(void) { /* * code here */} static void __exit cleanup_module(void) { /* * code here */}
2.6内核的驱动模版是 #include <linux/module.h> #include <linux/config.h> #include <linux/init.h> MODULE_LICENSE("GPL"); static int __init name_of_initialization_routine(void) { /* code goes here */ return 0; } static void __exit name_of_cleanup_routine(void) { /* code goes here */ } module_init(name_of_initialization_routine); module_exit(name_of_cleanup_routine);
(这个模版来源于ZDNET的一篇文档,但原文有些错误,可以在http://www.itpapers.com.cn/上搜索“Linux 2.6内核移植—硬件驱动篇”)
- Linux 2.6和2.4内核的字符设备驱动的注册方法不同,而且使用了dev_t这个设备ID的类型,提供了MAJOR(kdev_t dev)和MINOR(kdev_t dev)两个宏来获得设备的ID。
2.6内核的注册方法
A)静态注册 int register_chrdev_region(dev_t from, unsigned count, char *name); B)动态注册 int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, char *name);
之后需要和文件操作结构体联系起来 包含 <linux/cdev.h>,利用struct cdev和file_operations连接 struct cdev *cdev_alloc(void); oid cdev_init(struct cdev *cdev, struct file_operations *fops); int cdev_add(struct cdev *cdev, dev_t dev, unsigned count); 分别为,申请cdev结构,和fops连接,将设备加入到系统中.
删除设备: void cdev_del(struct cdev *cdev); 只有在cdev_add执行成功才可运行。
2.4内核的注册方法 int register_chrdev(unsigned major, char * name, struct file_operation * fops);
删除设备 int unregister_chrdev(unsigned major, char * name);
哈哈,好像2.4简单啊,为什么2.6要那么做呢?我的想法是这样的话字符设备可以不用和文件操作联系起来而用其他方法访问吧,不对的话不要笑我。但是在2.6内核中,register_chrdev仍然是可以用的。我看了下它的代码,是这样的:
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops) { struct char_device_struct *cd; struct cdev *cdev; char *s; int err = -ENOMEM;
cd = __register_chrdev_region(major, 0, 256, name); if (IS_ERR(cd)) return PTR_ERR(cd); cdev = cdev_alloc(); if (!cdev) goto out2;
cdev->owner = fops->owner; cdev->ops = fops; kobject_set_name(&cdev->kobj, "%s", name); for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/')) *s = '!'; err = cdev_add(cdev, MKDEV(cd->major, 0), 256); if (err) goto out;
cd->cdev = cdev;
return major ? 0 : cd->major; out: kobject_put(&cdev->kobj); out2: kfree(__unregister_chrdev_region(cd->major, 0, 256)); return err; }
整个过程不就是对register_chrdev_region、cdev_add之类函数的调用么,呵呵。
unsigned long tmp; unsigned long * pREG; // Note: pREG is a pointer which points to a 4-bytes long integer, "pREG + 4" is equal to // add 16-bytes offset to the physical address. // Added by Lu Xianzi 2007.5.29
pREG = ioremap(0x560000000, 0x20); tmp = * (volatile unsigned long *) (pREG + 4);
值得一提的是,pREG在驱动程序中应该是一个全局变量,在初始化时因该将其赋值,在模块卸载时应使用iounmap(ptr),来取消地址转换。 这种地址的映射不是简单的将一个地址转化为另一个地址,在内核中有一个表来记录这种映射,超过ioremap所注册范围大小的映射是不成立的,例如,访问0x56000080就不能在pREG的基础上简单的加上偏移(我的理解,FIXME)。
2.4内核是 #arm-linux-gcc -D__KERNEL__ -I[你的内核的位置]/include -DKBUILD_BASENAME=[你的模块的名字] -DMODULE -c -o [你要生成的模块文件的名字].o [驱动程序源文件的名字].c
2.6内核,必须在你的驱动程序源文件目录下建立一个Makefile,其中写上你要编译的源文件输出,如obj-m := [驱动程序源文件的名字].o,然后输入 # make -k -C [你的内核的位置] SUBDIRS=$PWD modules 2.4内核仅仅生成.o文件,2.6内核的模块扩展名是.ko。
挂载模块 insmod [模块文件的名字].ko 在文件系统中建立节点 mknod /dev/[你想建立的节点名字] c [MAJOR] [MINOR] 其中,MAJOR、MINOR分别是主和子设备号,MAJOR就是你register_chrdev时的那个MAJOR。 接下来就可以用open函数打开设备,用read,write,ioctl等函数访问设备,用close函数关闭设备,这些函数的原型在stdio.h中。
用户程序用open函数打开设备时,如果有写操作,请将open的参数设置为O_RDWR(是Operation的O,不是数字0,这个宏在fcntl.h中),如open("/dev/mydev", O_RDWR);,否则会出现write无法进行的错误。呵呵请恕我白痴,在这个问题上困扰很久。
|
在系统内部,I/O设备的存/取通过一组固定的入口点来进行,这组入口点是由每个设备的设备驱动程序提供的。具体到Linux系统,设备驱动程序所提供的这组入口点由一个文件操作结构来向系统进行说明。file_operations结构定义于linux/fs.h文件中,随着内核的不断升级,file_operations结构也越来越大,不同版本的内核会稍有不同。
struct file_operations
{
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int,\
unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*readv) (struct file *, const struct iovec *,\
unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *,\
unsigned long, loff_t *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t,\
loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long,\
unsigned long, unsigned long, unsigned long);
};
file_operations结构中的成员全部是函数指针,所以实质上就是函数跳转表。每个进程对设备的操作,都会根据major、minor设备号,转换成对file_operations结构的访问。
常用的操作包括以下几种:
lseek,移动文件指针的位置,只能用于可以随机存取的设备。
read,进行读操作,参数buf为存放读取结果的缓冲区,count为所要读取的数据长度。返回值为负表示读取操作发生错误;否则,返回实际读取的字节数。对于字符型,要求读取的字节数和返回的实际读取字节数都必须是inode-I_blksize的倍数。
write,进行写操作,与read类似。
select,进行选择操作。如果驱动程序没有提供select入口,select操作将会认为已经准备好进行任何的I/O操作。
ioctl,进行读、写以外的其他操作,参数cmd为自定义的命令。 |
简而言之,就是你在文件操作中使用的open,read,write,ioctl,close等,都会调用你在file_operation中定义的相应的函数入口。 5月25日 经过这么久,终于回到我写这个Blog的原因上了,我又开始搞ARM Linux了。
很后悔之前没有把很多问题写清楚,1年多了,我也忘得差不多了。幸好由于是虚拟机开发,Linux开发环境和我过去在Linux下写的代码在经历了几次系统重装后还健在,这个星期花了3~4天的时间基本上把之前的东西捡起来了。今天主要记录我遗漏的导致这个星期花很多时间整的内容。
首先是Source Navigator的安装,我想在本本上也来个Linux,安装Source Navigator的时候就遇到了问题。安装说明里如是说,解压之后:
mkdir snbuild cd snbuild ../sourcenav-5.20/configure --prefix=/opt/sourcenav make (become root) make install
我在错误的地方(解压之后的文件夹里)建立了snbuild,网上搜了下还有不少人和我犯同样错误,这个会导致说某个文件No rule to make的错误。 写个提示符带目录名的:
/home/lxz # tar xvzf sourcenav-5.2b2 -C ./ /home/lxz # mkdir snbuild /home/lxz # cd snbuild /home/lxz/snbuild # ../sourcenav-5.2b2/configure --prefix=/opt/sourcenav /home/lxz/snbuild # make (become root) /home/lxz/snbuild # make install
还有个错误,说什么“OSF*)”处Unexpected token )之类的,这个好像是Linux各种包安装的问题,另外路径错误好像也会有这个提示,我把Suse 10.1全部安装之后就没有这个问题了。
第二个,U-Boot网络下载内核、文件系统使用NFS,Windows下可以安装Omni NFS 5.2。这个软件的共享版支持2个用户连接,用来下载内核是足够了。另外使用Omni NFS的时候请把Windows防火墙禁用。
第三,之前我遇到的无法加载根文件系统或者说Busybox无法运行的问题已经找到原因了,有这几个方面共同作用: 1.S3C2410 NAND读写的ECC问题,必须取消ECC,或者使用Bootloader将NAND中的文件系统拷贝到RAM中做ramdisk 2.Busybox工作需要/lib下的共享库文件 3.Busybox静态库(即不使用/lib下的库文件)编译方式有问题 4.根文件系统中必须有“/dev”和“/mnt”,否则无法挂载console 目前我使用我的开发板自带的库文件,以及编译后的Busybox 1.00,成功加载root文件系统(cramfs格式,ramdisk)。解释下,ramdisk、bon、mtdblock是一个类别的东西,cramfs、jffs、yaffs、ext2是一个类别的东西,例如你可以在bon上用cramfs,也可以在ramdisk里用cramfs。
第四,mtdblock和bon的关系,目前我的理解是他们都是一种分区方式,当然需要相应的驱动,在vivi中用bon命令可以对NAND进行分区,如bon part add 0 192k 2m,bon命令分区过的NAND需要重新烧写vivi,而mtdblock分区的改变则不用。另外,bon和mtdblock信息是可以同时存在的。
第五,U-Boot的NAND WRITE命令在烧写NAND时不会自动擦除NAND Sector(vivi 会自动擦除的),需要手动进行,否则写入数据就不对了。
第六,ARM交叉编译器必须解压缩到/usr/local/arm,否则会提示编译器安装错误。
时隔一年,再次搞ARM Linux,发现能百度或者Google到的关于遇到的问题的中文文章还是这么少,甚至还有1997年的。希望我的这些琐事可以给你带来些帮助。 6月25日 这一个月来,我一直投身于Linux内核移植的伟大而光荣的事业,相当的痛苦了……
不过收获也是很大的,昨天晚上,哦应该是今天凌晨12:00,终于我的板子上出现了Busybox启动的好消息。Linux内核的移植终于取得了阶段性的成果,虽然后面的路还很长。
从我开始搞Linux,我就一直在网上或者图书馆中寻找“HOWTO”性质的文章,遗憾的是还真少。我也希望我的Blog成为我做的这块板子的“HOWTO”大全,呵呵。但是今天我不写“HOWTO”,对我的工作来个概括性的总结。
如果你是猎人的QQ群里过来看这个Blog,而且想获得与SBC2410X自带的VIVI和MIZI Linux的相关信息的,我很抱歉。我认为猎人板子里提供的资料实在是比较垃圾(实际上是友善之臂公司的资料),应该说是一些仅仅针对SBC2410X一种方式应用的“HOWTO”,而且没有提供其他方式应用的任何说明(呵呵,当然我没有责怪猎人的意思,这块板子硬件还是相当不错的,价钱也非常公道)。嵌入式系统的一个很大的特点就是其针对不同应用的可裁减性。举个例子,我希望把ARM用在机器人上,不需要网卡、声卡、USB,只需一个串口,用友善之臂给的资料能做什么?甚至连mkyaffsimage这个制作yaffs文件系统映像工具的源码都没有。其实其他厂家的也一样,可能这些所谓的开发板仅仅是一种技术垄断,尤其是那些动辄好几千块钱的。猎人提供的廉价开发板,我希望能通过我提供的这些开发资料,像开源工程一样,让更多的人受益。
作为一个初学者,最关心的是怎么下手。我先简要说明一下:
ARM Linux应该归类为一种非抢占式的分时多任务操作系统(相关术语可以Google一下),它不适合用来做伺服控制、图像处理等对系统实时性要求较高的控制。uCOS-II,VxWork可以胜任那样的工作。Linux的优点在于开源(Open Source)、网络支持和跨平台支持。其中我最看重的是跨平台支持。因为我的实验室经常使用DSP、单片机控制机器人,而这些程序不具有平台移植性,所以每届硕士做机器人的控制都是从学习DSP或单片机做起,相当浪费时间。我的工作的目的就是利用ARM、Linux、uCOS-II,设计ARM-DSP双核系统,搭建一个控制平台。
硬件环境就是必须购买一个ARM开发板,推荐买猎人的,这个与三星的SMDK2410这块“大众型”开发板完全兼容。搞嵌入式开发和普通的DSP、单片机开发不同,需要最多的是代码的移植,一个与“大众”系统兼容的开发板,可以节约移植别人编写的针对“大众”系统代码的时间。软件环境指的是需要有一台可以运行Linux的PC,以及PC的软件。这些软件包括gcc编译器、gcc交叉编译器(在PC平台编译非PC平台程序的编译器)、Linux NFS支持(用于网络下载内核到开发板)、Linux SMB支持(Linux访问Windows网络共享)、代码察看软件(例如Source Navigator)、Bootloader和内核源代码。其中前四项在安装Linux时候就必须选定,后几项从网络上获得。推荐在Windows下使用虚拟机建立开发系统,可以带来非常大的方便。具体的软硬件系统建立步骤“HOWTO”请看5月15日我写的文章。Linux内核和相应的编译器的下载地址我后面的文章会写出来。另外,有一定硬件电路开发经验的人会有需不需要仿真器的疑问,答案是:根本不需要也不可能用仿真器来调试,一个烧写电缆足以,除非你搞ARM7TDMI-S这种经过裁剪的ARM CPU的程序。主要的调试信息显示渠道是串口,主要的代码下载渠道是串口或者以太网——这由你的Bootloader决定,一个好的Bootloader可以大大减少内核调试的时间。我调试内核使用的是U-Boot的网络下载功能,800kB的内核只需要5~6秒就可以下载结束,我的开发板原配的VIVI的串口需要3分钟多,效率的差距显而易见,更不用说内核之后动辄几个或者几十个MB的文件系统了。
- 接下来就可以进行开发了,首先是Bootloader
Bootloader是系统上电以后执行的第一段程序,它主要的功能和作用有:初始化硬件,复制Linux内核和Ramdisk文件(如果使用的话)到内存中,把预先设定的内核参数传递给内核并启动,提供硬件诊断、Flash烧写、网络连接等功能。推荐使用U-Boot,U-Boot的下载地址 http://sourceforge.net/projects/u-boot。U-Boot的“HOWTO”可以看我5月23、30日写的文章。
还必须说明的是,通常从开源工程网站下来的都是软件的源码,需要自己进行编译。编译由源码目录下的“Makefile”这个文件决定,其中包含有关于编译的配置和操作类型的信息。一般用于多平台的源码,Makefile中都有CROSS_COMPILE这一项,在编译之前必须将它指定到交叉编译器。对于arm-linux-gcc这个交叉编译器,如果设置了指向arm-linux-gcc的缺省路径,可以填写CROSS_COMPILE=arm-linux-,注意,后面的“-”不可以少。通常由于开源代码的编译器兼容性太差,你需要在你的电脑里安装多个版本的交叉编译器,例如我的U-Boot用2.95.3编译器编译,而Linux内核用的是3.4.1,我设置2.95.3为默认编译器。对于使用非默认路径编译器的代码,可以填写CROSS_COMPILE到绝对路径,例如CROSS_COMPILE=/usr/local/arm/3.4.1/bin/arm-linux-。另外,Linux内核的Makefile还有一个ARCH选项要修改,以后说。
编译开源代码的一般步骤为:清除之前编译结果(clean)、设定编译配置(config)、编译(make)
1.清除之前编译结果
一般可以用:
# make clean
或者
# make distclean
这2种写法的区别在于,distclean不仅仅清除编译生成的*.o文件,而且还清除已经设定的编译配置。
2.设定编译配置
主要作用是将繁杂的代码进行组织,屏蔽所需编译目标不需用到的源代码文件,并将这个组织的结果保存下来。设定编译配置命令例如:
Linux内核编译的:
# make menuconfig
# make config
# make smdk2410_defconfig
U-Boot编译的:
# make smdk2410_config
menuconfig是最常用的一种方式,它将调用本机编译器(HOSTCC)产生一个交互的文本菜单式界面,对内核的编译选项、驱动支持、文件系统、调试、外设等进行设置。config是一个提问式的配置方式,很麻烦,不推荐使用。smdk2410_defconfig是针对三星的SMDK2410开发板的基本硬件进行配置,这可以节约一些配置内核的时间。类似这种xxxx_config的配置,体现了购买“大众”型开发板的优势,可以用最短的时间,建立起一套有效的嵌入式系统。
3.最后是编译
一般可以直接输入make。但是对于Linux2.4内核,之前还必须输入
# make dep
用以产生源代码之间的关联信息,2.6版本的内核不再需要这个步骤。
对于Linux内核,编译可以生成不同格式的映像文件,例如:
# make zImage
# make uImage
zImage是ARM Linux常用的一种压缩映像文件,uImage是U-boot专用的映像文件,它是在zImage之前加上一个长度为0x40的“头”,说明这个映像文件的类型、加载位置、生成时间、大小等信息。换句话说,如果直接从uImage的0x40位置开始执行,zImage和uImage没有任何区别。另外,Linux2.4内核不支持uImage,Linux2.6内核加入了很多对嵌入式系统的支持,但是uImage的生成也需要设置,这个以后我会介绍。
另外,我假设内核不采用任何模块。没有编译模块这一步。
内核的移植和调试是整个嵌入式系统开发中最麻烦的一步,建议如果没有良好的硬件和C语言基础,以及健壮的神经和充裕的时间,不要涉足内核的开发,尽可能采用网络上例如我的Blog中提供的现成方法,包括所有细节都要一一仿制,完成内核的移植。其实,这是考验你运气的一个环节,可能有的人一次就移植成功,可能有的人因为一些小小环节的问题,例如编译器版本问题、内核版本问题、代码修改输入错误之类的,遇到一些稀奇古怪的错误,卡住你的工作而无法继续。同时,这对你的耐心和毅力也是一个考验。呵呵,我被考验了一个月,也算是比较倒霉吧。内核修改和编译需要做的工作很多,由于Linux设备的驱动是集成在内核里的(当然还可以作为模块挂载,但是我不讨论模块问题),需要对内核代码进行修改。以后我会专门介绍。内核实现的功能是对硬件资源如内存、串口、液晶控制器的管理,以及对操作系统执行的任务程序的调度。
内核不能包括一个嵌入式系统所需的所有东西,例如程序,资料等,而且如果没有文件系统,对嵌入式系统工作过程产生信息的纪录也会成问题,所以一般的嵌入式Linux系统需要文件系统。当然没有文件系统内核也不是不能工作,这我就不太懂了,毕竟是个高深的问题……以我的跟踪内核运行认识来看,只要把你所需要执行的任务编译进内核,然后对初始化部分进行修改,让其在没有root文件系统的时侯继续下去,对你的任务进行调度也许就可以。
嵌入式Linux和PCLinux不同,一般嵌入式系统没有硬盘,所以传统的Linux文件系统如ext2,hpfs之类的不能用在嵌入式Linux上。常见的嵌入式文件系统有:romfs,cramfs,jffs,yaffs等,当然也可以通过Ramdisk使用ext2。这些文件系统的特性可以自己Google一下。
我最初接触到文件系统的时候,曾经有个很纯朴的想法,既然电脑硬盘上有文件系统,需要分区后格式化,那么嵌入式系统的Flash是不是也必须进行这样的操作呢,而且,分区表纪录在那里呢?在嵌入式Linux中,对Flash并不需要进行分区,目前我的解决方法是把“分区表”信息写入内核,然后直接在内核中分区表信息对应的Flash区域读写,这在内核中叫做MTD支持(Memomry Techonlogy Device),Flash同样需要擦除后写入相应内容——这可以通过Bootloader来完成,不像PC中用的是安装程序。
关于文件系统的建立,我还没有完全研究完,我仅仅是利用了从我的开发板原始文件系统中剥离的一个文件系统,还有很多错误,以后我会补充上文件系统建立的详细文章。
在这些总结背后,我做了许多工作,包括跟踪U-Boot启动Linux部分的代码,内核启动代码,内核初始化代码等。我利用了内核的一些汇编的接口,用以在内核启动过程中输出调试信息。如下:
这是保存寄存器的宏:
/* * Lu Xianzi's Kernel debugging macro */
#define LXZ_LL_DEBUG 1
.macro lxz_save_regs stmfd sp!, {r0-r12} .endm .macro lxz_restore_regs ldmfd sp!, {r0-r12} .endm
这是一个调用的例子:
/* =============================================================== * * Tracing code added by Lu Xianzi */ #ifdef LXZ_LL_DEBUG lxz_save_regs adr r0, lxz_str_into_creat_pt bl printascii adr r0, lxz_str_page_tbl_addr bl printascii mov r0, r4 bl printhex8 mov r0, #'\n' bl printch lxz_restore_regs b 1f lxz_str_into_creat_pt: .asciz "\nInto create page table section!\n" .align lxz_str_page_tbl_addr: .asciz "Page table address = " .align 1: #endif
/* =============================================================== */
需要提醒的是,printascii,printhex,printch这几个函数只是使用了r0~r3这几个寄存器。
跟踪内核的运行是一件非常痛苦的事情,但真能解决问题,而且学到很多东西。
今天先写到这里吧,改天继续。 5月30日 本来不应该先写这个的,呵呵,但是我这个人记忆力很差,说不定过几天我就忘了移植过程中的代码是哪里弄来的了。 
首先庆祝一下,我学生生涯所有的考试都结束了,哈哈哈。不过希望不要补考……听说我们的研究生教学院长赵学增老师的课很变态,120个抓50个……上帝保佑我啊。
开始吧。标准的SMDK2410板不支持NAND Flash,启动的时候是这样的:
U-Boot 1.1.2 (May 28 2006 - 08:20:50)
U-Boot code: 33F80000 -> 33F99A14 BSS: -> 33F9DB0C RAM Configuration: Bank #0: 30000000 64 MB Flash: 1 MB *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial
有NAND支持的多一行(NAND 64MB):
U-Boot 1.1.2 (May 28 2006 - 08:36:42)
U-Boot code: 33F80000 -> 33F99A14 BSS: -> 33F9DB0C RAM Configuration: Bank #0: 30000000 64 MB Flash: 1 MB NAND: 64 MB *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial
怎么实现这种支持呢?U-Boot真是功能强大的Bootloader,在/inclued/configs/smdk2410.h中有这么一段
/*********************************************************** * Command definition ***********************************************************/ #define CONFIG_COMMANDS \ (CONFIG_CMD_DFL | \ CFG_CMD_CACHE | \ CFG_CMD_NAND | \ /*CFG_CMD_EEPROM |*/ \ /*CFG_CMD_I2C |*/ \ /*CFG_CMD_USB |*/ \ CFG_CMD_REGINFO | \ CFG_CMD_DATE | \ CFG_CMD_ELF)
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
需要说明一下CONFIG_CMD_DFL,定义的是默认指令,包括bdinfo、bootd、coninfo、saveenv、flinfo、erase、protect、iminfo、imls、itest、loadb、loads、md、mm、nm、mw、cp、cmp、crc、base、loop、loopw、mtest、sleep、bootp、tftpboot、rarpboot、run等常用指令,这些指令我以后会结合使用做适当的说明。关于指令的宏定义说明可以看看U-Boot的README里面的Monitor Functions。这就是对编译成功后的U-Boot支持的命令的定义,SMDK2410默认的smdk2401.h中,红色字部分是注释掉的。但是要支持NAND Flash远没有去掉一个注释这么简单。
我们可以试试单纯把这个注释去掉是什么结果,老步骤:
make distclean
make smdk2410_config
make
……一堆编译信息飘过……
出错了,位置指向cmd_nand.c这个文件,好几处错误。原因是SMDK2410的配置里根本就没有对NAND Flash支持的宏定义和函数。怎么办?自己写么?好在U-Boot里有另外一个可以让我们借鉴的配置VCMA9。在Source Navigator里搜索一下vcma,看看vcma9.h和vcma9.c,可以从中摘取出一段宏定义和一些函数声明。网上有人的做法是将其放在smdk2410.h和smdk2410.c中,但是白痴的cross-2.95.3和cross-3.2都不能认到cmd_nand.c中已经在smdk2410.h和smdk2410.c中定义的宏所指的函数,就算是加上extern的也不行。也许你没有看懂刚才这句话,解释一下,例如cmd_nand.c中有这样一段
if(ale_wait) NAND_WAIT_READY(nand); /* do the worst case 25us wait */ else udelay(10);
其中NAND_WAIT_READY(nand),在smdk2410.h中定义为
#define NAND_WAIT_READY(nand) NF_WaitRB()
而NF_WaitRB()在smdk2410.c中定义为
static inline void NF_WaitRB(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
while (!(nand->NFSTAT & (1<<0))); }
这个编译器死活说NF_WaitRB()未定义,就算是我在cmd_nand.c中加上这样一句也不起作用
extern void NF_WaitRB(void)
也许是我C学的不好,搞不清楚多个文件共同编译的时候static inline的引用关系,不管它,我把这些宏中定义的函数的申明放在了cmd_nand.c中,为了不太无耻,我在前面加上了针对SMDK2410的选择性编译。(请注意,下面这些代码拷贝到cmd_nand.c中的适当位置,cmd_nand.c中有许多选择性编译的宏,注意放的位置,不要被忽略掉了)
/*----------------------------------------------------------------------- * NAND flash basic functions * Added by Lu Xianzi 2006.5.27 * Copied from board/mpl/vcma9/vcma9.h & vcma9.c */
#if (CONFIG_SMDK2410)
#include <s3c2410.h> typedef enum { NFCE_LOW, NFCE_HIGH } NFCE_STATE;
static inline void NF_Conf(u16 conf) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFCONF = conf; }
static inline void NF_Cmd(u8 cmd) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFCMD = cmd; }
static inline void NF_CmdW(u8 cmd) { NF_Cmd(cmd); udelay(1); }
static inline void NF_Addr(u8 addr) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFADDR = addr; }
static inline void NF_SetCE(NFCE_STATE s) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
switch (s) { case NFCE_LOW: nand->NFCONF &= ~(1<<11); break;
case NFCE_HIGH: nand->NFCONF |= (1<<11); break; } }
static inline void NF_WaitRB(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
while (!(nand->NFSTAT & (1<<0))); }
static inline void NF_Write(u8 data) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFDATA = data; }
static inline u8 NF_Read(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
return(nand->NFDATA); }
static inline void NF_Init_ECC(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFCONF |= (1<<12); }
static inline u32 NF_Read_ECC(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
return(nand->NFECC); }
extern ulong nand_probe(ulong physadr);
static inline void NF_Reset(void) { int i;
NF_SetCE(NFCE_LOW); NF_Cmd(0xFF); /* reset command */ for(i = 0; i < 10; i++); /* tWB = 100ns. */ NF_WaitRB(); /* wait 200~500us; */ NF_SetCE(NFCE_HIGH); }
static inline void NF_Init(void) { #if 0 /* a little bit too optimistic */ #define TACLS 0 #define TWRPH0 3 #define TWRPH1 0 #else #define TACLS 0 #define TWRPH0 4 #define TWRPH1 2 #endif
NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0)); /*nand->NFCONF = (1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0); */ /* 1 1 1 1, 1 xxx, r xxx, r xxx */ /* En 512B 4step ECCR nFCE=H tACLS tWRPH0 tWRPH1 */
NF_Reset(); }
void nand_init(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
NF_Init(); #ifdef DEBUG printf("NAND flash probing at 0x%.8lX\n", (ulong)nand); #endif printf ("%4lu MB\n", nand_probe((ulong)nand) >> 20); }
#endif /* (CONFIG_SMDK2410) */
然后把下面这些宏定义放在smdk2410.h中
/*----------------------------------------------------------------------- * NAND flash settings * Added by Lu Xianzi 2006.5.27 * Copied from include/conifgs/vcma9.h */ #if (CONFIG_COMMANDS & CFG_CMD_NAND)
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */ #define SECTORSIZE 512
#define ADDR_COLUMN 1 #define ADDR_PAGE 2 #define ADDR_COLUMN_PAGE 3
#define NAND_ChipID_UNKNOWN 0x00 #define NAND_MAX_FLOORS 1 #define NAND_MAX_CHIPS 1
#define NAND_WAIT_READY(nand) NF_WaitRB()
#define NAND_DISABLE_CE(nand) NF_SetCE(NFCE_HIGH) #define NAND_ENABLE_CE(nand) NF_SetCE(NFCE_LOW)
#define WRITE_NAND_COMMAND(d, adr) NF_Cmd(d) #define WRITE_NAND_COMMANDW(d, adr) NF_CmdW(d) #define WRITE_NAND_ADDRESS(d, adr) NF_Addr(d) #define WRITE_NAND(d, adr) NF_Write(d) #define READ_NAND(adr) NF_Read() /* the following functions are NOP's because S3C24X0 handles this in hardware */ #define NAND_CTL_CLRALE(nandptr) #define NAND_CTL_SETALE(nandptr) #define NAND_CTL_CLRCLE(nandptr) #define NAND_CTL_SETCLE(nandptr)
/* #define CONFIG_MTD_NAND_VERIFY_WRITE 1 */
/* This definition above is commented by Lu Xianzi. 2006.05.28 Because there's no definition of a macro called __mem_pci, there will be a link error. */ #define CONFIG_MTD_NAND_ECC_JFFS2 1
#endif /* CONFIG_COMMANDS & CFG_CMD_NAND */
注意这段宏定义中与vcma9.h中不同的是我标记红色的部分,网上的一些移植说明没有解决这个问题,导致最后的链接无法通过。事实上,我这样做取消了cmd_nand.c中对NAND Flash的写校验和ECC校验。__mem_pci是一个什么东西我也不知道,在U-Boot目录下搜索包含“__mem_pci”字串的文件也没有找到,除了使用它的/include/asm/io.h。顺便说一下,这个麻烦是从cmd_nand.c中的nand_write_page函数中readb(nand->IO_ADDR)这个宏开始的,你可以用Source Navigator查找一下引用,最后就指向没有__mem_pci宏的这个问题。希望有高手看到这篇文章,并给我指出解决的办法,呵呵。 
做完这些修改,就再来一次老步骤
make distclean
make smdk2410_config
make
………………
生成了U-Boot.bin。NAND Flash的驱动到此完成,好不好使呢?试试看。上次我们已经在板子里烧写进了U-Boot,是一个可以支持串口传输的U-Boot,要是现在还用sjf2410往里烧U-Boot.bin就太冤大头了。可以利用串口进行传输,操作步骤如下:
使用超级终端,建立一个连接:文件〉新建连接;名称随便,图表随便,确定;连接时使用选择你的开发板所接的COM口;端口设置中,每秒位数选115200,数据位选8,奇偶校验选无,停止位选1,数据流控制选“无”。打开开发板的电源,出现以下提示:
U-Boot 1.1.2 (May 28 2006 - 08:20:50)
U-Boot code: 33F80000 -> 33F99A14 BSS: -> 33F9DB0C RAM Configuration: Bank #0: 30000000 64 MB Flash: 1 MB *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial
LXZROB # loadb
## Ready for binary (kermit) download to 0x33000000 at 115200 bps...
loadb这个指令以kermit协议从串口下载二进制文件到开发板的内存中,默认下载到0x33000000。当然你可以改在别的地址,例如:loadb 30000000就是下载到0x30000000。这时候选择超级终端菜单上:传送〉发送文件,文件名选择编译好的U-Boot.bin,协议选择Kermit,点发送。可以看到发送进度。
发送结束出现提示:
## Total Size = 0x00019a14 = 104980 Bytes ## Start Addr = 0x33000000
这时可以测试新的修改好不好使:
LXZROB # go 33000000 ## Starting application at 0x33000000 ...
U-Boot 1.1.2 (May 28 2006 - 08:36:42)
U-Boot code: 33F80000 -> 33F99A14 BSS: -> 33F9DB0C RAM Configuration: Bank #0: 30000000 64 MB Flash: 1 MB NAND: 64 MB *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial LXZROB #
go指令可以直接执行内存地址上的程序,例如刚才下载到0x33000000的新的支持NAND的U-Boot,可以看到出现了“NAND: 64MB”这一项。输入help,你会看到比刚才的U-Boot多了一组指令nand,输入help nand,可以看到更加细节的指令:
LXZROB # help nand nand info - show available NAND devices nand device [dev] - show or set current device nand read[.jffs2[s]] addr off size nand write[.jffs2] addr off size - read/write `size' bytes starting at offset `off' to/from memory address `addr' nand erase [clean] [off size] - erase `size' bytes from offset `off' (entire device if not specified) nand bad - show bad blocks nand read.oob addr off size - read out-of-band data nand write.oob addr off size - read out-of-band data
输入nand info,可以看到:
LXZROB # nand info
Device 0: Samsung unknown 64Mb at 0x4e000000 (64 MB, 16 kB sector)
说明我们的驱动成功了。也可以试试其他指令。
但是现在在NOR Flash中的U-boot还是不支持NAND的,需要重新烧写。U-Boot支持自己烧写自己。
先看看NOR Flash的情况:
LXZROB # flinfo
Bank # 1: AMD: 1x Amd29LV800BB (8Mbit) Size: 1 MB in 19 Sectors Sector Start Addresses: 00000000 (RO) 00004000 (RO) 00006000 (RO) 00008000 (RO) 00010000 (RO) 00020000 00030000 00040000 00050000 00060000 00070000 00080000 00090000 000A0000 000B0000 000C0000 000D0000 000E0000 000F0000 (RO)
一共有19个sector,其中前5个总计128kb的sector有U-Boot程序,是写保护的。要烧写首先要去掉写保护:
LXZROB # protect off 0 1ffff Un-Protected 5 sectors LXZROB # flinfo
Bank # 1: AMD: 1x Amd29LV800BB (8Mbit) Size: 1 MB in 19 Sectors Sector Start Addresses: 00000000 00004000 00006000 00008000 00010000 00020000 00030000 00040000 00050000 00060000 00070000 00080000 00090000 000A0000 000B0000 000C0000 000D0000 000E0000 000F0000 (RO)
可以看到写保护已经去掉,擦除:
LXZROB # erase 0 1ffff Erasing sector 0 ... ok. Erasing sector 1 ... ok. Erasing sector 2 ... ok. Erasing sector 3 ... ok. Erasing sector 4 ... ok. Erased 5 sectors
然后烧写:
LXZROB # cp.b 33000000 0 19a14 Copy to Flash... done
cp.b是用来拷贝内存信息的,其格式为cp [.b, .w, .l] source target count,输入这样的指令是因为刚才把程序下载到了0x33000000,NOR Flash的起始地址是0x0,下载的程序长度为0x19a14。重启开发板,U-Boot的烧写就完成了。 5月27日 今天发现我的交叉编译器不好使了,呵呵,用snapshot恢复。
重新解压缩交叉编译器,发现有问题,原来是KDE带的图形界面解压缩器的问题,用指令来
tar jxvf cross-2.95.3.tat.bz2 -C /usr/local/arm
这是一个。
另外,今天研究出了让路径设置永久起作用的方法,打开/etc/profile,做如下修改(本修改仅仅针对SUSE)
# # Make path more comfortable #
# 先找到这个注释 if test -z "$PROFILEREAD" ; then PATH=/usr/local/bin:/usr/bin:/usr/X11R6/bin:/bin if test "$HOME" != "/" ; then for dir in $HOME/bin/$CPU $HOME/bin ; do test -d $dir && PATH=$dir:$PATH done fi test "$UID" = 0 && PATH=/sbin:/usr/sbin:/usr/local/sbin:$PATH for dir in /var/lib/dosemu \ /usr/games \ /opt/bin \ /opt/gnome/bin \ /opt/kde3/bin \ /opt/kde2/bin \ /opt/kde/bin \ /usr/openwin/bin \ /opt/cross/bin \ /usr/local/arm/2.95.3/bin
# 加上你的交叉编译器所在的路径 do test -d $dir && PATH=$PATH:$dir done unset dir export PATH fi 5月23日 最近考试好忙,明天还要去长春出差,郁闷,周五考我学生生涯的最后一科——机械动力学。
希望你看了我上一篇Blog,呵呵。这篇是继续的。我假设你已经建立了我推荐的开发环境。
今天文章里所有的图片在相册“5-23 U-BOOT针对SMDK2410的移植”里面。
给大家秀一下我的SUSE。(5-23 SUSE)
工作开始了,先把U-boot解压缩到你喜欢的地方。然后打开Source Navigator,选择New Project。在接下来的窗口中,选择一个你喜欢的Project File的名字,然后在Add Directory里选择你把U-Boot1.1.2解压缩到的那个目录。再选择OK。然后等等,U-Boot这个变态的东西有143MB大……接下来出现了一个窗口。(5-23 SNAV启动)这个窗口里列出了U-Boot所有的源代码文件。上面的Pattern是为了便于你查找某个文件输入文件名的地方。
U-Boot是一种通用的Bootloader,它支持很多种不同的板子。我用的SBC2410X(友善之臂的)就是它支持的SMDK2410开发板的一种衍生。U-BOOT同时支持自定义配置的开发板,具体的配置方法参见U-Boot目录下的Readme文件。U-Boot关于各种板子的配置文件放在/board目录下,我们的SMDK2410也在那里具体的目录是/board/smdk2410,其下有主要几个文件:flash.c——关于NORFLASH操作的函数;config.mk——指定U-BOOT代码重新加载的基址;memsetup.s——汇编语言写的内存初始化程序,在start.s中调用,以后介绍;smdk2410.c——SMDK2410目标板初始化等函数。还有一个重要的文件是在U-Boot目录/include/configs下的smdk2410.h,包含了很多对目标板设置的宏。这几个文件中的配置与移植的目标板严格对应,如果你在SMDK2410的基础上重新设计了目标板硬件,那就必须修改这些文件中的相关内容。
其实有了Source-Navigator这些文件的位置就变得无关紧要了,你只要在Pattern中输入你要查找的文件的前缀,文件就会列出在下面的列表中。你就输入smdk2410,回车,出现了2个文件:smdk2410.c和smdk2410.h,刚开始移植不需要搞太复杂的东西,只修改smdk2410.h就可以了。smdk2410.h的内容和要修改的地方(红色)如下:
/* * (C) Copyright 2002 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> * Marius Groeger <mgroeger@sysgo.de> * Gary Jennejohn <gj@denx.de> * David Mueller <d.mueller@elsoft.ch> * * Configuation settings for the SAMSUNG SMDK2410 board. * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */
#ifndef __CONFIG_H #define __CONFIG_H
/* * If we are developing, we might want to start armboot from ram * so we MUST NOT initialize critical regs like mem-timing ... */ #define CONFIG_INIT_CRITICAL /* undef for developing */
/* * High Level Configuration Options * (easy to change) */ #define CONFIG_ARM920T 1 /* This is an ARM920T Core */ #define CONFIG_S3C2410 1 /* in a SAMSUNG S3C2410 SoC */ #define CONFIG_SMDK2410 1 /* on a SAMSUNG SMDK2410 Board */
/* input clock of PLL */ #define CONFIG_SYS_CLK_FREQ 12000000/* the SMDK2410 has 12MHz input clock */
#define USE_920T_MMU 1 #undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */
/* * Size of malloc() pool */ #define CFG_MALLOC_LEN (CFG_ENV_SIZE + 128*1024) #define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */
/* * Hardware drivers */ #define CONFIG_DRIVER_CS8900 1 /* we have a CS8900 on-board */ #define CS8900_BASE 0x19000300 #define CS8900_BUS16 1 /* the Linux driver does accesses as shorts */
/* * select serial console configuration */ #define CONFIG_SERIAL1 1 /* we use SERIAL 1 on SMDK2410 */
/************************************************************ * RTC ************************************************************/ #define CONFIG_RTC_S3C24X0 1
/* allow to overwrite serial and ethaddr */ #define CONFIG_ENV_OVERWRITE
#define CONFIG_BAUDRATE 115200
/*********************************************************** * Command definition ***********************************************************/ #define CONFIG_COMMANDS \ (CONFIG_CMD_DFL | \ CFG_CMD_CACHE | \ /*CFG_CMD_NAND |*/ \ /*CFG_CMD_EEPROM |*/ \ /*CFG_CMD_I2C |*/ \ /*CFG_CMD_USB |*/ \ CFG_CMD_REGINFO | \ CFG_CMD_DATE | \ CFG_CMD_ELF)
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */ #include <cmd_confdefs.h>
#define CONFIG_BOOTDELAY 3 /*#define CONFIG_BOOTARGS "root=ramfs devfs=mount console=ttySA0,9600" */ #define CONFIG_ETHADDR 08:00:3e:26:0a:5b #define CONFIG_NETMASK 255.255.255.0 #define CONFIG_IPADDR 202.202.202.218
//你的开发板的IP地址 #define CONFIG_SERVERIP 202.202.202.118
//你的运行Linux的电脑的IP地址
//这些设定解决的是网络下载程序的问题 /*#define CONFIG_BOOTFILE "elinos-lart" */ /*#define CONFIG_BOOTCOMMAND "tftp; bootm" */
#if (CONFIG_COMMANDS & CFG_CMD_KGDB) #define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */ /* what's this ? it's not used anywhere */ #define CONFIG_KGDB_SER_INDEX 1 /* which serial port to use */ #endif
/* * Miscellaneous configurable options */ #define CFG_LONGHELP /* undef to save memory */ #define CFG_PROMPT "LXZROB # " /* Monitor Command Prompt */
//开发板命令提示符,你可以改成你喜欢的任何字符串 #define CFG_CBSIZE 256 /* Console I/O Buffer Size */ #define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */ #define CFG_MAXARGS 16 /* max number of command args */ #define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */
#define CFG_MEMTEST_START 0x30000000 /* memtest works on */ #define CFG_MEMTEST_END 0x33F00000 /* 63 MB in DRAM */
#undef CFG_CLKS_IN_HZ /* everything, incl board info, in Hz */
#define CFG_LOAD_ADDR 0x33000000 /* default load address */
/* the PWM TImer 4 uses a counter of 15625 for 10 ms, so we need */ /* it to wrap 100 times (total 1562500) to get 1 sec. */ #define CFG_HZ 1562500
/* valid baudrates */ #define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 }
/*----------------------------------------------------------------------- * Stack sizes * * The stack sizes are set up in start.S using the settings below */ #define CONFIG_STACKSIZE (128*1024) /* regular stack */ #ifdef CONFIG_USE_IRQ #define CONFIG_STACKSIZE_IRQ (4*1024) /* IRQ stack */ #define CONFIG_STACKSIZE_FIQ (4*1024) /* FIQ stack */ #endif
/*----------------------------------------------------------------------- * Physical Memory Map */ #define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */ #define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */ #define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */
#define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */
#define CFG_FLASH_BASE PHYS_FLASH_1
/*----------------------------------------------------------------------- * FLASH and environment organization */
#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */ #if 0 #define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */ #endif
//NORFLASH定义,使用的是1MByte的还是512kByte的
#define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */ #ifdef CONFIG_AMD_LV800 #define PHYS_FLASH_SIZE 0x00100000 /* 1MB */ #define CFG_MAX_FLASH_SECT (19) /* max number of sectors on one chip */ #define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */ #endif #ifdef CONFIG_AMD_LV400 #define PHYS_FLASH_SIZE 0x00080000 /* 512KB */ #define CFG_MAX_FLASH_SECT (11) /* max number of sectors on one chip */ #define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x070000) /* addr of environment */ #endif
/* timeout values are in ticks */ #define CFG_FLASH_ERASE_TOUT (5*CFG_HZ) /* Timeout for Flash Erase */ #define CFG_FLASH_WRITE_TOUT (5*CFG_HZ) /* Timeout for Flash Write */
#define CFG_ENV_IS_IN_FLASH 1 #define CFG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */
#endif /* __CONFIG_H */
代码中红色的地方是我修改过的,可以对比原始的文件,就可以看出不同。
修改完了以后别忘了保存,然后到终端下面,输入
make distclean
……一堆E文飘过……
make smdk2410_config
Configuring for smdk2410 board...
make
……一堆E文连绵不断的飘过,你可以喝喝水,嗑瓜子……
如果没有错误的话,就会在U-Boot目录下生成U-Boot.bin文件。如果有错误,恭喜你,你的麻烦事情来了。只要你按照我这篇文章和上篇文章的步骤来做,不会有错误的。值得注意的是,必须使用U-Boot1.1.2和arm-linux交叉编译器2.95.3 ,另外看看是不是之前路径没有设置,即
export PATH=/usr/local/arm/2.95.3/bin:$PATH没有输入,呵呵,还是没有研究明白SUSE的config怎么改。
下载时选择Utility中的SEC JTAG Flash(SJF) NAND,NOR(AMD,Strata) Flash。当然,如果你买了开发板,一般就会带有这个烧写程序了,不需费心下载,这里只是告诉你最本源的出处。
推荐在Windows的虚拟DOS环境中完成烧写,命令格式sjf2410 /f:u-boot.bin。烧写速度很慢,大约需要10分钟。烧写完成后,将启动选择跳线跳到NORFlash,重启开发板,串口就有输出了。串口调试工具推荐使用Windows自带的超级终端(程序〉附件〉通讯〉超级终端),下面是U-BOOT启动的提示信息:
U-Boot 1.1.2 (May 22 2006 - 02:30:03)
U-Boot code: 33F80000 -> 33F98380 BSS: -> 33F9C47C RAM Configuration: Bank #0: 30000000 64 MB Flash: 1 MB *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial LXZROB #
输入help可以看到U-Boot的操作指令列表:
? - alias for 'help' autoscr - run script from memory base - print or set address offset bdinfo - print Board Info structure boot - boot default, i.e., run 'bootcmd' bootd - boot default, i.e., run 'bootcmd' bootelf - Boot from an ELF image in memory bootm - boot application image from memory bootp - boot image via network using BootP/TFTP protocol
bootvx - Boot vxWorks from an ELF image
cmp - memory compare coninfo - print console devices and information cp - memory copy crc32 - checksum calculation date - get/set/reset date & time dcache - enable or disable data cache echo - echo args to console erase - erase FLASH memory flinfo - print FLASH memory information go - start application at address 'addr' help - print online help icache - enable or disable instruction cache iminfo - print header information for application image imls - list all images found in flash itest - return true/false on integer compare loadb - load binary file over serial line (kermit mode) loads - load S-Record file over serial line loop - infinite loop on address range md - memory display mm - memory modify (auto-incrementing) mtest - simple RAM test mw - memory write (fill) nfs - boot image via network using NFS protocol nm - memory modify (constant address) printenv- print environment variables protect - enable or disable FLASH write protection rarpboot- boot image via network using RARP/TFTP protocol reset - Perform RESET of the CPU run - run commands in an environment variable saveenv - save environment variables to persistent storage setenv - set environment variables sleep - delay execution for some time tftpboot- boot image via network using TFTP protocol version - print monitor version
|