基于S3C2410的Linux全线移植文档
超高兴,我们团队自己的文档。
已上传到附件中 (edit by platinum)
欢迎转载此pdf文档,如有不明之处可以向文档当中各部分负责团队成员发邮件。
目录:
第一部分 前言
第二部分 系统启动bootloader的编写(ADS)
第三部分 GNU交叉工具链
第四部分 u-boot的移植
第五部分 linux 2.6内核的移植
第六部分 应用程序的移植
第七部分 Nand flash驱动的编写与移植
[ 本帖最后由 dozec 于 2006-7-26 15:10 编辑 ]
附件:
linux_mig_release.pdf (2006-7-26 10:00, 1.09 M)
该附件被下载次数 185
__________________________________
ARM-内核-存储
Q:17541461
BLOG:http://blog.csdn.net/dozec/
MAIL:[url=mailto:[email protected]][email protected][/url](有事发MAIL吧)
看了platinum兄弟写的在2.4内核下给iptables添加模块,想在2.6的内核下也试试,经过一天半的努力,并参考platinum兄弟的文章,
终于成功,写下来跟CU的兄弟们分享,我的系统为fedora2+linux-2.6.5-1.358
1,安装kernel源码
[root@jiecho]# yum install kernel-source
2,下载iptables-1.3.3.tar.bz2和patch-o-matic-ng-20050810.tar.bz2并解包,为了方便,我们都放在/usr/src下,
并把kernel和iptables做符号链接.
[root@jiecho]# cd /usr/src
[root@jiecho]# wget ftp://ftp.be.netfilter.org/pub/netfilter/iptables/iptables-1.3.3.tar.bz2
[root@jiecho]# wget ftp://ftp.be.netfilter.org/pub/netfilter/patch-o-matic-ng/snapshot/patch-o-matic-ng-20050810.tar.bz2
[root@jiecho]# tar -jxvf iptables-1.3.3.tar.bz2
[root@jiecho]# tar -jxvf patch-o-matic-ng-20050810.tar.bz2
[root@jiecho]# ln -s linux-2.6.5-1.358 linux
[root@jiecho]# ln -s iptables-1.3.3 iptables
3,给netfilter打补丁,选择你要的模块,为了测试我就选择了ipp2p和time
[root@jiecho]# cd /usr/src/linux
[root@jiecho]# make mrproper
[root@jiecho]# make menuconfig
什么不做,保存退出,然后把Makefile改一下
[root@jiecho]# vi Makefile
把EXTRAVERSION = -1.358custom更改为EXTRAVERSION = -1.358
保持跟uname -a 的版本一致(可详细参考platinum兄弟的文章)
[root@jiecho]# cd /usr/src/patch-o-matic-ng-20050810
[root@jiecho]# ./runme ipp2p
[root@jiecho]# ./runme time
因为事先做好了符号链接,等问你kernel和iptables的位置的时候直接回车就行,
提示你是否添加ipp2p和time模块是就y确定,至此,netfilter的补丁打完了,如果你需要别的模块可以根据需要加上.
4,编译kernel的modules
[root@jiecho]# cd /usr/src/linux
[root@jiecho]# make menuconfig
在Device Drivers->;Networking support->;Networking options->;Network packet filtering (replaces ipchains)
->;IP: Netfilter Configuration中把下面的两项M选中.
; TIME match support
; IPP2P match support
然后保存退出
4,编译安装模块
下面就是最重要的步骤了,因为我们的原则是节省时间,不重新编译内核,而只编译其中的模块,
这点2.4的内核跟2.6的内核有所不同,郁闷了我一整天,2.4内核的模块是以*.o形式的,而2.6内核是以*.ko形式的,
这有个改变的方法,参考:http://blog.chinaunix.net/articl ... 742&blogId=2662
[root@jiecho]# make modules
HOSTCC scripts/basic/fixdep
HOSTCC scripts/basic/split-include
HOSTCC scripts/basic/docproc
HOSTCC scripts/conmakehash
HOSTCC scripts/kallsyms
CC scripts/empty.o
HOSTCC scripts/mk_elfconfig
MKELF scripts/elfconfig.h
HOSTCC scripts/file2alias.o
HOSTCC scripts/modpost.o
HOSTCC scripts/sumversion.o
HOSTLD scripts/modpost
HOSTCC scripts/pnmtologo
HOSTCC scripts/bin2c
到这里就可以ctrl+c中止了,因为我们不是要编译所有的模块,这样太浪费时间,而仅仅是netfilter的模块,
但是如果你直接执行make modules SUBDIRS=net/ipv4/netfilter就会出错,这就是2.4和2.6的区别,
我们先生成了scripts目录下的一系列需要的文件后就可以make modules SUBDIRS=net/ipv4/netfilter,
并用modpost等等把*.o文件生成为*.ko文件.
[root@jiecho]# make modules SUBDIRS=net/ipv4/netfilter
编译完成netfilter的模块后拷贝编译完成的模块
[root@jiecho]# cp /usr/src/linux/net/ipv4/netfilter/ipt_ipp2p.ko /lib/modules/2.6.5-1.358/kernel/net/ipv4/netfilter/
[root@jiecho]# cp /usr/src/linux/net/ipv4/netfilter/ipt_time.ko /lib/modules/2.6.5-1.358/kernel/net/ipv4/netfilter/
[root@jiecho]# chmod +x /lib/modules/2.6.5-1.358/kernel/net/ipv4/netfilter/ipt_ipp2p.ko
[root@jiecho]# chmod +x /lib/modules/2.6.5-1.358/kernel/net/ipv4/netfilter/ipt_time.ko
[root@jiecho]# depmod -a
5,编译iptables
[root@jiecho]# cd /usr/src/iptables
参照INSTALL文件我们进行编译安装
[root@jiecho]# make KERNEL_DIR=/usr/src/linux
会有错误编译不过
/usr/src/linux/include/linux/config.h:6:2: [root@jiecho]#error including kernel header in userspace; use the glibc headers instead!
我google了半天也没有找到是什么原因,就自己动手解决
[root@jiecho]# vi /usr/src/linux/include/linux/config.h把下面的三行注释掉
//#ifndef __KERNEL__
//#error including kernel header in userspace; use the glibc headers instead!
//#endif
然后重新编译安装
make KERNEL_DIR=/usr/src/linux
make install KERNEL_DIR=/usr/src/linux
完成安装以后测试一下
[root@jiecho]# iptables -V
[root@jiecho]# modprobe ipt_time
[root@jiecho]# modprobe ipt_ipp2p
[root@jiecho]# lsmod
ipt_time 2432 0
ipt_ipp2p 7552 0
ipt_REJECT 4736 1
ipt_state 1536 1
ip_conntrack 24968 1 ipt_state
iptable_filter 2048 1
ip_tables 13440 5 ipt_time,ipt_ipp2p,ipt_REJECT,ipt_state,iptable_filter
battery 6924 0
ipv6 184288 10
3c59x 30376 0
binfmt_misc 7176 1
nls_utf8 1536 4
ntfs 81516 4
dm_mod 33184 0
uhci_hcd 23708 0
button 4504 0
asus_acpi 8472 0
ac 3340 0
ext3 102376 4
jbd 40216 1 ext3
测试iptables
[root@jiecho]# iptables -A FORWARD -m ipp2p --edk --kazaa --bit -j DROP
[root@jiecho]# iptables -A INPUT -m time --timestart 8:00 --timestop 18:00 --days Mon,Tue,Wed,Thu,Fri
[root@jiecho]# iptalbes -L
是不是中断处理程序就永远不能继续执行了?
俗话说:"功夫不负有心人",通过编译Linux内核时才能真正体会到.曾经也失败过无数次,放弃过一段时间编译.最后通过自己不断的实践和在网上收集这方面资料,终于在前不久编译成功了.把我在网上收集的资料和自己编译的过程整理了一下,拿来和大家分享一下,希望能给有这方面需要的同仁以帮助,好让大家少走弯路.
言归正传:
环境:VMware5.0 for windows(在新建虚拟机向导的"虚拟机磁盘类型"本人选的是IDE)
内核版本:kernel2.6.13(原内核是字符模式,不包括xwindow模式)
原来的系统是redhat9.0,内核2.4.20-8,编译的内核2.6.13,仅供参考.
共分为四部分:编译前准备->;编译配置->;编译过程->;运行内核的常见问题
一 编译前准备
1)下载一份内核源代码,我下的版本是linux-2.6.13.tar.gz,你可在如下地址下载它或者是更新的版本.
http://www.kernel.org/pub/linux/kernel/v2.6/
2) 下载最新版本的module-init-tools( "module-init-tools-3.0.tar.gz" and "modutils-2.4.21-23.src.rpm")
http://www.kernel.org/pub/linux/ ... it-tools-3.0.tar.gz
http://www.kernel.org/pub/linux/ ... s-2.4.21-23.src.rpm
3)安装modutils-2.4.21-23.src.rpm. 你可能会看到"user rusty and group rusty not existing"的警告. 没关系,你只需强制安装就是了.如果你不对Redhat 9和Redhat 8做这几步, 你将会在"make modules_install"这一步时出现问题.
#rpm -e --nodeps modutils (强行卸载原有的modutilsRPM包)
#rpm -ivh modutils-2.4.21-23.src.rpm (把源代码包安装到了/usr/src/redhat目录下)
#cd /usr/src/redhat/SPECS (进入规范文件目录下)
#rpmbuild --bb modutils.spec (生成二进制的RPM包)
#cd ../RPMS/i386 (转入刚生成的二进制的RPM包所在位置)
#rpm -ivh modutils*.rpm (刚生成两个[modutils-2.4.21-23.i386.rpm与modutils-debuginfo-2.4.21.23.i386.rpm]二进制的RPM包,一起安装吧!)
4)安装module-init-tools. 它会替代depmod [/sbin/depmod]和其他工具.
tar -zxvf module-init-tools-3.0.tar.gz
cd module-init-tools-3.0
./configure --prefix=/sbin
make
make install
./generate-modprobe.conf /etc/modprobe.conf
5)解压缩内核源代码.把下载的源代码包放到目录/usr/src下,然后
cd /usr/src
tar –zvxf linux-2.6.13.tar.gz
ln –s linux-2.6.13 linux
cd linux
6)make mrproper
该命令确保源代码目录下没有不正确的.o文件以及文件的互相依赖。由于我们使用刚下载的完整的
源程序包进行编译,所以本步可以省略。而如果你多次使用了这些源程序编译内核,那么最好要先运行
一下这个命令
7)
犎繁/usr/include/目录下的asm、linux和scsi等链接是指向要升级的内核源代码的。它们分别链向源代码目录下的真正的、该计算机体系结构(对于PC机来说,使用的体系结构是i386)所需要的真正的
include子目录。如:asm指向/usr/src/linux/include/asm-i386等。若没有这些链接,就需要手工创建
,按照下面的步骤进行:
# cd /usr/include/
# rm -r asm linux scsi
# ln -s /usr/src/linux/include/asm-i386 asm
# ln -s /usr/src/linux/include/linux linux
# ln -s /usr/src/linux/include/scsi scsi
这是配置非常重要的一部分。删除掉/usr/include下的asm、linux和scsi链接后,再创建新的链接
指向新内核源代码目录下的同名的目录。这些头文件目录包含着保证内核在系统上正确编译所需要的重
要的头文件。现在你应该明白为什么我们上面又在/usr/src下"多余"地创建了个名为linux的链接了吧?
*******************************************************************
编译linux2.6.14的仁兄们注意了,如果是按本人的帖子上的步骤,请将以上第7)步
去掉,否则运行make menuconfig会出现以下错误
HOSTCC scripts/basic/split-include
In file included from /usr/include/linux/errno.h:4,
from /usr/include/bits/errno.h:25,
from /usr/include/errno.h:36,
from scripts/basic/split-include.c:26:
/usr/include/asm/errno.h:4:31: asm-generic/errno.h: 没有那个文件或目录
make[1]: *** [scripts/basic/split-include] Error 1
make: *** [scripts_basic] Error 2
*************************************************************
二 编译配置
在这一部分涉及几个重要模块的配置请,特别注意.一般用"make menuconfig"命令来配置内核.
进入图形模式
#startx
接下来的内核配置过程比较烦琐,但是配置的适当与否与日后Linux的运行直接相关,有必要了解一下一
些主要的且经常用到的选项的设置。
牐犈渲媚诤丝梢愿据需要与爱好使用下面命令中的一个:
#make config(基于文本的最为传统的配置界面,不推荐使用)
#make menuconfig(基于文本选单的配置界面,字符终端下推荐使用)
#make xconfig(基于图形窗口模式的配置界面,Xwindow下推荐使用)
#make oldconfig(如果只想在原来内核配置的基础上修改一些小地方,会省去不少麻烦)
牐犝馊个命令中,make xconfig的界面最为友好,如果你可以使用Xwindow,那么就推荐你使用这个命
令。
牐犎绻你不能使用Xwindow,那么就使用make menuconfig好了。界面虽然比上面一个差点,总比make
config的要好多了。
牐犙≡裣嘤Φ呐渲檬保有三种选择,它们分别代表的含义如下:
Y--将该功能编译进内核
N--不将该功能编译进内核,也不编成模块
M--将该功能编译成可以在需要时动态插入到内核中的模块
牐犎绻使用的是make xconfig,使用鼠标就可以选择对应的选项。如果使用的是make menuconfig,则
需要使用空格键进行选取。你会发现在每一个选项前都有个括号, 但有的是中括号有的是尖括号,还有
一种圆括号。 用空格键选择时可以发现,中括号里要么是空,要么是"*",而尖括号里可以是空,"*"和
"M"这表示前者对应的项要么不要,要么编译到内核里;后者则多一样选择,可以编译成模块。而圆括号
的内容是要你在所提供的几个选项中选择一项。
牐犜诒嘁肽诤说墓程中,最烦杂的事情就是这步配置工作了,很多新手都不清楚到底该如何选取这些
选项。实际上在配置时,大部分选项可以使用其缺省值,只有小部分需要根据用户不同的需要选择。选
择的原则是将与内核其它部分关系较远且不经常使用的部分功能代码编译成为可加载模块,有利于减小
内核的长度,减小内核消耗的内存,简化该功能相应的环境改变时对内核的影响;不需要的功能就不要
选;与内核关心紧密而且经常使用的部分功能代码直接编译到内核中。下面就让我们对常用的选项分别
加以介绍。
8.1. Code maturity level options
牐牬码成熟等级。此处只有一项:prompt for development and/or incomplete code/drivers,如果
你要试验现在仍处于实验阶段的功能,比如khttpd、IPv6等,就必须把该项选择为Y了;否则可以把它选
择为N。
牐8.2. Loadable module support
牐牰阅?榈闹С帧U饫锩嬗腥项:
牐燛nable loadable module support:除非你准备把所有需要的内容都编译到内核里面,否则该项应
该是必选的。
牐燬et version information on all module symbols:可以不选它。
牐燢ernel module loader:让内核在启动时有自己装入必需模块的能力,建议选上。
8.3. Processor type and features
牐燙PU类型。内容蛮多的,不一一介绍了,有关的几个如下:
牐燩rocessor family:根据你自己的情况选择CPU类型。
牐燞igh Memory Support:大容量内存的支持。可以支持到4G、64G,一般可以不选。
牐燤ath emulation:协处理器仿真。协处理器是在386时代的宠儿,现在早已不用了。
牐燤TTR support:MTTR支持。可不选。
牐燬ymmetric multi-processing support:对称多处理支持。除非你富到有多个CPU,否则就不用选了
。
牐8.4. General setup
牐犝饫锸嵌宰钇胀ǖ囊恍┦粜越行设置。这部分内容非常多,一般使用缺省设置就可以了。下面介绍
一下经常使用的一些选项:
牐燦etworking support:网络支持。必须,没有网卡也建议你选上。
牐燩CI support:PCI支持。如果使用了PCI的卡,当然必选。
牐燩CI access mode:PCI存取模式。可供选择的有BIOS、Direct和Any,选Any吧。
牐燬upport for hot-pluggabel devices:热插拔设备支持。支持的不是太好,可不选。
牐燩CMCIA/CardBus support:PCMCIA/CardBus支持。有PCMCIA就必选了。
牐燬ystem V IPC
牐燘SD Process Accounting
牐燬ysctl support:以上三项是有关进程处理/IPC调用的,主要就是System V和BSD两种风格。如果你
不是使用BSD,就按照缺省吧。
牐燩ower Management support:电源管理支持。
牐燗dvanced Power Management BIOS support:高级电源管理BIOD支持。
牐8.5. Memory Technology Device(MTD)
牐燤TD设备支持。可不选。
牐8.6. Parallel port support
牐牬口支持。如果不打算使用串口,就别选了。
牐8.7. Plug and Play configuration
牐牸床寮从弥С帧K淙籐inux对即插即用目前支持的不如Windows好,但是还是选上吧,这样你可以拔
下鼠标之类的体验一下Linux下即插即用的感觉。
牐8.8. Block devices
牐牽樯璞钢С帧U飧鼍偷谜攵宰约旱那榭隼囱×耍简单说明一下吧:
牐燦ormal PC floppy disk support:普通PC软盘支持。这个应该必选。
牐燲T hard disk support:
牐燙ompaq SMART2 support:
牐燤ulex DAC960/DAC1100 PCI RAID Controller support:RAID镜像用的。
牐燣oopback device support:
牐燦etwork block device support:网络块设备支持。如果想访问网上邻居的东西,就选上。
牐燣ogical volume manager(LVM)support:逻辑卷管理支持。
牐燤ultiple devices driver support:多设备驱动支持。
牐燫AM disk support:RAM盘支持。
牐8.9. Networking options
牐犕络选项。这里配置的是网络协议。内容太多了,不一一介绍了,自己看吧,如果你对网络协议有
所了解的话,应该可以看懂的。如果懒得看,使用缺省选项(肯定要选中TCP/IP networking哦)就可以
了。让我们看看,TCP/IP、ATM、IPX、DECnet、Appletalk……支持的协议好多哦,IPv6也支持了,Qos
and/or fair queueing(服务质量公平调度)也支持了,还有kHTTPd,不过这些都还在实验阶段。
牐8.10. Telephony Support
牐牭缁爸С帧U飧鍪鞘裁炊东?让我查查帮助,原来是Linux下可以支持电话卡,这样你就可以在IP上
使用普通的电话提供语音服务了。记住,电话卡可和modem没有任何关系哦。
牐8.11. ATA/IDE/MFM/RLL support
牐犝飧鍪怯泄馗髦纸涌诘挠才/光驱/磁带/软盘支持的,内容太多了,使用缺省的选项吧,如果你使用
了比较特殊的设备,比如PCMCIA等,就到里面自己找相应的选项吧。
,比如PCMCIA等,就到里面自己找相应的选项吧。
8.12. SCSI support
牐燬CSI设备的支持。我没有SCSI的设备,所以根本就不用选,如果你用了SCSI的硬盘/光驱/磁带等设
备,自己找好了。
牐8.13. IEEE 1394(FireWire)support
牐犝飧鍪鞘裁矗康桶姹镜拿挥屑过,看看帮助再说。原来是要Fireware硬件来提高串行总线的性能,
我没有,不选了。
牐8.14. I2O device support
牐犝飧鲆膊磺宄,帮助里说是这个需要I2O接口适配器才能支持的,在智能Input/Output(I2O)体系
接口中使用,又是要硬件,不选了。
牐8.15. Network device support
牐犕络设备支持。上面选好协议了,现在该选设备了,可想而知,内容肯定多得很。还好还好,里面
大概分类了,有ARCnet设备、Ethernet(10 or 100 Mbit)、Ethernet(1000Mbit)、Wireless LAN
(non-hamradio)、Token Ring device、Wan interfaces、PCMCIA network device support几大类。
我用的是10/100M的以太网,看来只需要选则这个了。还是10/100M的以太网设备熟悉,内容虽然多,一
眼就可以看到我所用的RealTeck RTL-8139 PCI Fast Ethernet Adapter support,为了免得麻烦,编译
到内核里面好了,不选M了,选Y。耐心点,一般说来你都能找到自己用的网卡。如果没有,你只好自己
到厂商那里去要驱动了。
牐8.16. Amateur Radio support
牐犛忠桓霾欢的,应该是配置业余无线广播的吧,没有,不要了。
牐8.17. IrDA(infrared)support
牐犝飧鲆红外支持,免了。
牐8.18. ISDN subsystem
牐犎绻你使用ISDN上网,这个就必不可少了。自己看着办好了。
牐8.19. Old CD-ROM drivers(not SCSI、not IDE)
牐犠龅目烧嬷艿剑原来那些非SCSI/IDE口的光驱谁还在用啊,自己选吧,反正我是用的IDE的CD-ROM,
不选这个。
牐8.20. Character devices
牐犠址设备。这个内容又太多了,先使用缺省设置,需要的话自己就修改。把大类介绍一下吧:
牐營2C support:I2C是Philips极力推动的微控制应用中使用的低速串行总线协议。如果你要选择下面
的Video For Linux,该项必选。
牐燤ice:鼠标。现在可以支持总线、串口、PS/2、C&T 82C710 mouse port、PC110 digitizer pad,
自己根据需要选择。
牐燡oysticks:手柄。即使在Linux下把手柄驱动起来意义也不是太大,游戏太少了。
牐燱atchdog Cards:虽然称为Cards,这个可以用纯软件来实现,当然也有硬件的。如果你把这个选中
,那么就会在你的/dev下创建一个名为watchdog的文件,它可以记录你的系统的运行情况,一直到系统
重新启动的1分钟左右。有了这个文件,你就可以恢复系统到重启前的状态了。
牐燰ideo For Linux:支持有关的音频/视频卡。
牐燜tape, the floppy tape device driver:
牐燩CMCIA character device support:
牐8.21. File systems
牐犖募系统。内容又太多了,老法子,在缺省选项的基础上进行修改。介绍以下几项:
牐燪uota support:Quota可以限制每个用户可以使用的硬盘空间的上限,在多用户共同使用一台主机
的情况中十分有效。
牐燚OS FAT fs support:DOS FAT文件格式的支持,可以支持FAT16、FAT32。
牐營SO 9660 CD-ROM file system support:光盘使用的就是ISO 9660的文件格式。
牐燦TFS file system support:ntfs是NT使用的文件格式。
牐/proc file system support:/proc文件系统是Linux提供给用户和系统进行交互的通道,建议选上
,否则有些功能没法正确执行。
牐牷褂辛硗馊个大类都规到这儿了:Network File Systems(网络文件系统)、Partition Types(分
区类型)、Native Language Support(本地语言支持)。值得一提的是Network File Systems里面的两
种:NFS和SMB分别是Linux和Windows相互以网络邻居的形式访问对方所使用的文件系统,根据需要加以
选择。
牐8.22. Console drivers
牐牽刂铺ㄇ动。一般使用VGA text console就可以了,标准的80*25的文本控制台。
牐8.23. Sound
牐犐卡驱动。如果你能在列表中找到声卡驱动那自然最好,否则就试试OSS了。
牐8.24. USB supprot
牐燯SB支持。很多USB设备,比如鼠标、调制解调器、打印机、扫描仪等,在Linux都可以得到支持,根
据需要自行选择。
牐8.25. Kernel hacking
牐犈渲昧苏飧觯即使在系统崩溃时,你也可以进行一定的工作了。普通用户是用不着这个功能的。
牐犠芩闩渲猛炅耍现在存盘退出,当然你也可以把现在的配置文件保存起来,这样下次再配置的时候就省力气了。
三 编译过程牐
在繁杂的配置工作完成以后,下面你就可以自己到杯茶耐心等候了。与编译有关的命令有如下几个:
#make clean --删除不必要的模块和文件
#make bzImage --开始编译系统内核
#make modules --开始编译外挂模块
#make modules_install --安装编译完成的模块
下面是生成配置
#make install
这里如果出现 "NO MODULE BUSLOGIC FOUND",解决方法
第1种方法:
编辑文件 /etc/modules.conf
将"alias scsi hostadapter BusLogic"这行注释掉,
即#alias scsi hostadapter BusLogic
保存 /etc/modules.conf,退出
# make install
第2种方法:
手动添加启动项
#depmod -a
#cp /usr/src/linux/System.map /boot/System.map-2.6.13
#cp /usr/src/linux/arch/i386/bzImage /boot/vmlinuz-2.6.13
四 运行内核的常见问题
1. 编译完后不启动,报以下错误:
VFS: Cannot open root device "LABEL=/" or 0.0
>; Please append a correct "root=" boot option
>; kernel panic: VFS: Unable to mount root fs
如果是上面的错误,请确认你把如下选项配置进kernel
(1) 如果/使用了EXT3 文件系统,在内核中要加入EXT3的支持
(2)如果是IDE的硬盘必须要IDE的驱动加载
(3)在block devices--RAM disk support 中选取 Initial disk(initrd) support,有时在mount / 之前
需要加载一些模块,这些modules 被做到一个镜像文件中--kernel-ver.img 中,这个文件位于/boot.举个例子,如果EXT3 的是以模块加载的话,在mount / 时就需要用到它,所以系统就在initrd.kernel-ver.img 中寻找它.
使用命令 mkinitrd initrd.kernel-ver.img kernel-ver 可以生成initrd.kernel-ver.img
2. 系统启动过程中加载iptables时报错的处理方法
修改/etc/rc.sysinit文件:
将其中所有的/proc/ksyms替换为/proc/kallsyms。
将其中所有的/proc/sys/kernel/modprobe 替换为/sbin/modprobe
在文件中mount -f /proc这一句下添加mount -f /sys
在文件中的action $"Mounting proc filesystem: " mount -n -t proc /proc /proc 这一句的下面添加 action $"Mounting sysfs filesystem: " mount -n -t sysfs /sys /sys
修改/etc/fstab文件:
加入none /sys sysfs defaults 0 0
修改/etc/init.d/halt文件:
将halt_get_remaining函数内的awk '$2 ~ /^//$|^//proc|^//dev/{next}改为
awk '$2 ~ /^//$|^//proc|^//sys|^//dev/{next}
创建目录:
mkdir /sys
然后重启机器,模块的问题应该解决的差不多了。
到这里编译工作顺利结束了.以上是本人在编译内核过程中遇到的问题以及解决方法,有些问题没有遇到,就没有写进去,希望大家给予补充指正,充分弘扬Linux精神!!!
3.RPM问题
进入编译好的内核后,与RPM相关的命令有些不能使用,并出现下列错误:
rpmdb: unable to join the environment
error: db4 error(11) from dbenv->open: Resource temporarily unavailable
error: cannot open Packages index using db3 - Resource temporarily unavailable (11)
error: cannot open Packages database in /var/lib/rpm
no packages
解决方法是执行“export LD_ASSUME_KERNEL=2.2.25”命令,也可以将其写入/etc/bashrc。
注本文引用文章:
(1)http://www.linuxfans.org/nuke/mo ... ewtopic&t=80658
(2)http://www.icwin.net/ShowArtitle.asp?art_id=10&cat_id=16
(3)http://www.linuxfans.org/nuke/mo ... topic&p=4409655
[ 本帖最后由 e2agle 于 2006-3-28 16:14 编辑 ]
下载地址
ed2k://|file|Base_SPB155.md5|418|099FDAFDC400AF42FB67BC5BF0F48709|h=5Y6IRQQV4GZALBQ6WM6K2TJ4TWKC7PTR|/
ed2k://|file|Base_SPB155_license.lic|4417|9B199204E91D2EDDB92F735BF4252867|h=5QZV3ZHIWSXFEU6X4BOCFBFMEQDSVEAT|/
ed2k://|file|Base_SPB155_lnx86_1of5.tar|385138176|D910778AE0ECC61737302C76E6057ABC|h=MC5HMZP2PW3OJBJTWEAHFVUHTOYHVVEK|/
ed2k://|file|Base_SPB155_lnx86_2of5.tar|559300096|523E2131409905281E6B5258FACBBA15|h=N2Q4V4FWNYBC3QOETLZRBQQO6GHOTOTT|/
ed2k://|file|Base_SPB155_lnx86_3of5.tar|562261504|F50832E3CFFE58B7FB63393DADECC171|h=MQ6HHIDBHRHEJOOEGK6DZVK4GYGVISSS|/
ed2k://|file|Base_SPB155_lnx86_4of5.tar|556144640|0CDBFA4E44044B5092FD814414EE6D5C|h=6IULH7ZJI4GQPAKNOY4DYOQD74PLNKNE|/
ed2k://|file|Base_SPB155_lnx86_5of5.tar|18953728|EEA2EF952BAC328A44807836CDB7555B|h=ZRNRPB43LVWHPGQJXSY64TPK5HGY3Z7D|/
_________________
SPB15.5的安装(libc要有低于2.3.5的版本)
cd cdrom1/E024_SPB155_ln86_1of5
./SETUP.SH
出现
Specify path of install directory [OR type [RETURN] to exit]:
输入/opt/spb
出现 Directory /opt/spb does not exist. Create? [y/n]: y
Do you want to use InstallScape [y/n]:n
Specify path of install directory [OR type [RETURN] to exit]: 回车
cd /opt/spb/install/bin.lnx86
./softload
开始安装
选1-1-2-cdrom1/E024_SPB155_ln86_1of5
出现
Please press y (yes) or n (no) : no
选
4) Cadence Catalog
再选a
再选y
出现
Your package selections require SPB155 lnx86 P/N 356-73303-0102 CDROM # 2.
1) 2)
3) SPB155 lnx86 P/N 356-73303-0102 CDROM # 2 already mounted on /home/chenqs/cdrom1/E024_SPB155_ln86_1of5, continue.
4) Change CD-ROM mount point.
m) Main Menu
Type your choice:
选责4出现
You must now identify where the CD-ROM is mounted.
1) Local (mounted to this machine)
在选1出现
Specify the CD-ROM mount point
1) /cdrom
2) Other
选2写入你2盘的位置就ok了。装好后
cd /opt/spb/install
ln -s tools.lnx86 tools
以候运行
空格 .空格 bashrc就可以了
allegro &allegro_design_entry_HDL &projmgr &用于起动程序.
Cadence.Allegro.v13.6 之后就改名叫PSD了,后来又改名叫SPB.
fc4 的tar和安装不兼容会出The following tar errors were detected:
装过程是
./SETUP.SH
1)装载可供使用的产品
你必须现在识别CD-ROM在什么地方被安装。
1)本地(安装到这台机器)
2)远程(安装到另一个机器)
m)主要的菜单
h)帮助
打出你的选择: [ 1 ]
规定CD-ROM安装点
1) / cdrom
2)其它
m)主要的菜单
p)以前的菜单
h)帮助
打出你的选择: [ 2 ]
2
从CD#1摘录安装信息。
你想要察看自述文件吗?
请压y (是)或者n (没有): n
安装信息是在什么地方?
1) (难以获得的选择)工作秩序
2)电子邮件文件
3)磁带
4)计算机辅助设计目录
5)文件目录
h)帮助
p)以前的菜单
q)退出
打出你的选择: [ 4 ]
a)所有上述
n)没有上述
p)以前的菜单
打出你的选择( a,n,p,1-3,2 5 9 ... ):a
你不有选择任何产品。
正确的这吗? [ y与n ]请压y (是)或者n (没有):
你的选择是正确的吗? [ y与n ]
请压y (是)或者n (没有) :y
产生详尽的设施数据...
确定可供使用的盘空间
确定需要的盘空间
如果出SL-13是:安装选择的不足的盘空间。
装好后
ln -s tools.lnx86 tools
/opt/psb/tools/pcb/bin/allegro.exe
我的bashrc如下
# Cadence PSD environment icq 111290069
export CDS_INST_DIR=/opt/psb
export CDS_LIC_FILE=$CDS_INST_DIR/share/cadence.license
export CDS_DIR=$CDS_INST_DIR
export CONCEPT_INST_DIR=$CDS_DIR
export CDS_SITE=$CDS_DIR/share/local/
export LD_LIBRARY_PATH=$LD_LIBRARY_PATHCONCEPT_INST_DIR/tools/lib
export CDSDOC_PROJECT=/CDS_INST_DIR/doc
PATH=/opt/spb/tools/jre/binCONCEPT_INST_DIR/tools/binCONCEPT_INST_DIR/tools/pcb/binCONCEPT_INST_DIR/tools/fet/binPATH
由于接触和使用较早等原因,国内的Protel用户为数众多,他们在选择Cadence高速PCB解决方案的同时,都面临着如何将手头的Protel设计移植到Cadence PCB设计软件中的问题。
转到linux下做PCB
由于接触和使用较早等原因,国内的Protel用户为数众多,他们在选择Cadence高速PCB解决方案的同时,都面临着如何将手头的Protel设计移植到Cadence PCB设计软件中的问题。
在这个过程当中碰到的问题大致可分为两种:一是设计不很复杂,设计师只想借助Cadence CCT的强大自动布线功能完成布线工作;二是设计复杂,设计师需要借助信噪分析工具来对设计进行信噪仿真,设置线网的布线拓扑结构等工作。
对于第一种情况,要做的转化工作比较简单,可以使用Protel或Cadence提供的Protel到CCT的转换工具来完成这一工作。对于第二种情况,要做的工作相对复杂一些,下面将这种转化的方法作一简单的介绍。
[email protected]
Cadence信噪分析工具的分析对象是Cadence Allegro的brd文件,而Allegro可以读入合乎其要求的第三方网表,Protel输出的Telexis格式的网表满足Allegro对第三方网表的要求,这样就可以将Protel文件注入Allegro。
这里有两点请读者注意。首先,Allegro第三方网表在$PACKAGE段不允许有“.”;其次,在Protel中,我们用BasName[0:N]的形式表示总线,用BasName[x]表示总线中的一根信号,Allegro第三方网表中总线中的一根信号的表示形式为Bas NameX,读者可以通过直接修改Protel输出的Telexis网表的方法解决这些问题。
Allegro在注入第三方网表时还需要每种类型器件的设备描述文件Device.txt文件,它的格式如下:
Package: package type
Class: classtype
Pincount: total pinnumber
Pinused: ...
其中常用的是PACKAGE,CLASS,PINCOUNT这几项。PACKAGE描述了器件的封装,但Allegro在注入网表时会用网表中的PACKAGE项而忽略设备描述文件中的这一项。CLASS确定器件的类型,以便信噪分折,Cadence将器件分为IC,IO,DISCRETE三类。PINCOUNT说明器件的管脚数目。对于大多数器件,Device.txt文件中包含有这三项就足够了。
有了第三方网表和设备描述文件,我们就可以将Protel中原理图设计以网表的形式代入到Cadence PCB设计软件中,接下来,设计师就可以借助Cadence PCB软件在高速高密度PCB设计方面的强大功能完成自己的设计。
如果已经在Protel作了PCB布局的工作,Allegro的script功能可以将Protcl中的布局在Allegro中重现出来。在Protel中,设计师可以输出一个Place & Pick文件,这个文件中包含了每个器件的位置、旋转角度和放在PCB顶层还是底层等信息,可以通过这个文件很方便的生成一个Allegro的script文件,在Allegro中执行这个script就能够重现Protel中的布局了,下面给出了完成Place & Pick文件到Allegro Script文件转化的C++代码,笔者使用这段代码,仅用了数分钟就将一个用户有800多个器件的PCB板布局在Allegro重现出来。
FILE *fp1, *fp2;
::AfxMessageBox("hello");
fp1=fopen("pick.txt", "rt");
if (fp1==NULL) ::AfxMessageBox("Can not open the file!!!");
fp2=fopen("place.txt","wt");
if (fp2==NULL) ::AfxMessageBox("Can not create the file!!!");
char refdes[5], Pattern[5];
float midx,midy,refx,refy,padx,pady,rotation;
char tb[1];
char tmp='"';
fprintf(fp2,"%s ", "# Allegro script");
fprintf(fp2,"%s ", "version 13.6");
fprintf(fp2,"%s ", "place refdes");
while (!feof(fp1)) {
fscanf(fp1,"%s", refdes);
fscanf(fp1,"%s", Pattern);
fscanf(fp1,"%f", &midx);
fscanf(fp1,"%f", &midy);
fscanf(fp1,"%f", &refx);
fscanf(fp1,"%f", &refy);
fscanf(fp1,"%f", &padx);
fscanf(fp1,"%f", &pady);
fscanf(fp1,"%s", tb);
fscanf(fp1,"%f", &rotation);
fprintf(fp2, "fillin %c%s%c ",tmp,refdes,tmp);
if (rotation!=0) {
fprintf(fp2, "rotate ");
fprintf(fp2, "iangle %f ", rotation);
};
char yy=tb[0];
if (yy!='T') fprintf(fp2, "pop mirror ");
fprintf(fp2, "pick %f %f ", padx,pady);
fprintf(fp2, "next ");
};
fprintf(fp2, "done");
fclose(fp1);
fclose(fp2);
以上简单介绍了Protel到 SPB152转化的方法,希望能对读者的设计工作有所帮助。'
[ 本帖最后由 wheel 于 2006-7-7 12:19 编辑 ]
__________________________________
郵政編碼:100054
地址:中國 北京市宣武區廣安門南街48號中彩大廈
5层509室
010-80900674
没人理?
http://www.wudilong.com/ssb/forumdisplay.php?fid=53&sid=GFOpqM
__________________________________
郵政編碼:100054
地址:中國 北京市宣武區廣安門南街48號中彩大廈
5层509室
010-80900674
呵呵,终于搞完了,把它发到一个贴子中来,做了一些修改……其中还有一些错误,希望大家指正,偶好修改!!!
——————————————————————————————————
《我也来学做嵌入式Linux系统V0.1》
作者:九贱
E-mail:[email protected]
个人站点:www.skynet.org.cn
___________________________________________________
第一章 前言
目的
本文的目的,是讲述嵌入式Linux系统的建立、开发的一般过程。制作一个小型的Linux的系统,可以移植至其它硬盘、软盘、优盘、flash rom……
关于作者
九贱,E名kendo,喜欢网络入侵技术、防火墙、入侵检测技术及网络技术,对Linux也颇感兴趣,想认识有共同爱好的朋友。最近闲暇,把一些学过的东西写下来,总结总结,以作备忘这需。已完成的有《网络入侵检测设计与Snort2.2源码分析》和这篇《我也来学做嵌入式Linux》。正在进行中的有《Windows防火墙技术实现大全》和《Linux防火墙实现及源码分析》。大家可以在CU上,或者是到我的小站www.skynet.org.cn上与我交流
做一个嵌入式Linux系统究竟要做哪些工作
做一个嵌入式Linux系统究竟需要做哪些工作?也就是本文究竟要讲述哪些内容?我先介绍一个脉络,可以做为我们后面工作的一个总的提纲:
第一步、建立交叉编译环境
没有交叉开发经验的读者,可能一时很难接受这个概念。首先,要明白两个概念:一般我们工作的机器,称为开发机、主机;我们制作好的系统将要放到某台机器,如手机或另一台PC机,这台机我们称为目标主机。
我们一般开发机上已经有一套开发工具,我们称之为原生开发套件,我们一般就是用它们来写程序,那么,那什么又是交叉编译环境呢?其实一点也不神秘,也就是在开发机上再安装一套开发工具,这套开发工具编译出来的程序,如内核、系统工作或者我们自己的程序,是放在目标主机上运行的。
那么或许有初学者会问,直接用原生开发工具为目标主机编译程序不就完了?至少我当初是这么想的。一般来说,我们的开发机都是X86平台,原生开发套件开发的工具,也针对X86平台,而我们的目标主机可能是PowerPC、IXP、MIPS……所以,我们的交叉编译环境是针对某一类具体平台的。
一般来讲,交叉开发环境需要二进制工具程序、编译器、C链接库,嵌入式开发常用的这三类软件是:
Binutils
Gcc
uClibc
当然,GNU包含的工具套件不仅于此,你还要以根据实际需要,进行选择
第二步、编译内核
开发工具是针对某一类硬件平台,内核同样也是。这一步,我们需要用第一步中建立的工具,对内核进行编译,对于有内核编译经验的人来说,这是非常简单的;
第三步、建立根文件系统
也就是建立我们平常看到的bin、dev、proc……这一大堆目录,以及一些必备的文件;另外,我们还需要为我们的目标系统安装一些常用的工具软件,如ls、ifconfig……当然,一个办法是找到这些工具的源代码,用第一步建立的交叉编译工具来编译,但是这些软件一是数量多,二是某些体积较大,不适合嵌入式系统,这一步,我们一般都是用busybox来完成的,包括系统引导软件init;
最后,我们为系统还需要建立初始化的引导文件,如inittab……
第四步、启动系统
在这一步,我们把建立好的目标、文件、程序、内核及模块全部拷贝到目标机存储器上,如硬盘。然后为系统安装bootloader,对于嵌入式系统,有许多引导程序可供我们使用。不过它们许多都有硬件平台的限制。当然,如果你是工作在X86,可以直接用lilo来引导,事实上,本文就是采用的lilo。
做到这一步,将目标存储设备挂上目标机,如果顺利,就可以启动系统了。
当然,针对某些特别的平台,不能像硬盘这样拷贝了,需要读卡器、烧录……但是基本的方法是相通的!
第五步、优化和个性化系统
通过前四步,我们已经得到了一个可以正常工作的系统。在这一步里,就是发挥你想像的时候了……
本文的工作环境
项目根目录/home/kendo/project ------>;我将它指定至PATHPRJROOT
子目录及说明
目录 内容
bootloader 目标板的引导加载程序,如lilo等
build-tools 建立交叉编译平台的工具源码
debug 调试工具及所有相关包
doc 项目中用到的所有文档
images 编译好的内核映像,以及根文件系统
kernel 各个版本的Linux内核源码
rootfs 制作好的根文件系统
sysapps 目标板将要用到的系统应用系统,比如thttpd,udhcpd等
tmp 存放临时文件
tools 编译好的跨平台开发工具链以及C链接库
工作的脚本
#!/usr/bin
export PROJECT=skynet
export PRJROOT=/home/${PROJECT}
export TARGET=i386-linux
export PREFIX=${PRJROOT}/tools
export TARGET_PREFIX=${PREFIX}/${TARGET}
export PATH=${PREFIX}/bin:/bin:/sbin:/usr/bin:/usr/sbin
cd $PRJROOT
第二章 建立交叉编译环境
在CU中发表的另一篇同名的贴子里,我讲述了一个全手工创建交叉编译环境的方法。目前,创建交叉编译环境,包括建立根文件,一般来讲,有两种方法:
手功创建
可以得到最大程序的个性化定制,缺点是过程繁杂,特别是极易出错,注意这个“极”字,包括有经验的开发人员;
自动创建
无它,方便而。
因为前一篇文章中,已经讲述了全手工创建交叉编译环境的一般性方法,本文就不打算再重复这个步骤了,感兴趣的朋友,可以再去搜索那篇贴子,提醒一点的就是,在准备工具链的时候,要注意各个工具版本之间的搭配、每个工具需要哪些补丁,我建议你在google上针对这两项搜索一下,准备一个清单,否则……
本章要讲述的是自动创建交叉编译环境的方法。目标,针对商业硬件平台,厂家都会为你提供一个开发包,我用过XX厂家的IXP425和MIPS的,非常地方便,记得我第一次接触嵌入式开发,拿着这个开发包自动化创建交叉编译环境、编译内核、建立根文件系统、创建Ram Disk,我反复做了三四次,结果还不知道自己究竟做了些什么,呵呵,够傻吧……
所以,建议没有这方面经验的读者,还是首先尝试一下手工创建的方法吧,而本章接下来的内容,是送给曾经被它深深伤害而不想再次去亲历这项工作而又想提高交率而又在通用平台上工作没有商业开发包的朋友。
建立交叉开发工具链
准备工具:
buildroot-0.9.27.tar.tar
只需要一个软件?对,其它的不用准备了,buildroot事实上是一个脚本与补丁的集合,其它需要用到的软件,如gcc、uClibc,你只需在buildroot中指明相应的版本,它会自动去给你下载。
事实上,buildroot到网上去下载所需的所有工作是需要时间的,除非你的带宽足够,否则下载软件时间或许会占去80%,而我在做这项工作之间,所需的工作链全部都在我本地硬盘上,我解压开buildroot后,新建dl文件夹,将所有工具源码的压缩包拷贝进去,呵呵,buildroot就不用去网上下载了。
我的软件清单:
Linux-libc-headers-2.4.27.tar.bz2
Gcc-3.3.4.tar.bz2
binutils 2.15.91.0.2.tar.bz2
uClibc 0.9.27.tar.bz2
genext2fs_1.3.orig.tar.gz
ccache-2.3.tar.gz
将它拷贝到${PRJROOT}/build-tools下,解压
[root@skynet build-tools]# tar jxvf buildroot-0.9.27.tar.tar
[root@skynet build-tools]#cd buildroot
配置它:
[root@skynet build-tools]#make menuconfig
Target Architecture (i386) --->; 选择硬件平台,我的是i386
Build options --->; 编译选项
这个选项下重要的是(${PRJROOT}/tools) Toolchain and header file location?编译好的工具链放在哪儿?
如果你像我一样,所有工具包都在本地,不需它到网上自动下载,可以把wget command选项清空;
Toolchain Options --->; 工具链选项
--- Kernel Header Options 头文件它会自动去下载,不过应该保证与你将要用的内核是同一个版本;
[] Use the daily snapshot of uClibc? 使用最近的uClibc的snapshot
Binutils Version (binutils 2.15.91.0.2) --->; Binutils的版本
GCC compiler Version (gcc 3.4.2) --->; gcc 版本
Build/install c++ compiler and libstdc++?
[ ] Build/install java compiler and libgcj? 支持的语言,我没有选择java
[ ] Enable ccache support? 启用ccache的支持,它用于编译时头文件的缓存处理,用它来编译程序,第一次会有点慢,但是以后的速度可就很理想了,呵呵……
--- Gdb Options 根据你的需要,选择gdb的支持
Package Selection for the target --->;
这一项我没有选择任意一项,因为我打算根文件系统及busybox 等工具链创建成工,手工来做。
Target Options --->; 文件系统类型,根据实际需要选,我用的ext2;
配置完成后,编译它:
[root@skynet build-tools]#make
这一项工作是非常花时间的,我的工具包全部在本地,也花去我一小时十三分的时间,如果全要下载,我估计网速正常也要多花一两个钟头。
经过漫长的等待(事实上并不漫长,去打了几把游戏,很快过去了):
……
make[1]: Leaving directory `/home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3'
touch -c /home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3/genext2fs
[url=mailto:#-@find]#-@find[/url] /home/skynet/build-tools/buildroot/build_i386/root/lib -type f -name /*.so/* | xargs /home/skynet/tools/bin/i386-linux-uclibc-strip --remove-section=.comment --remove-section=.note --strip-unneeded 2>;/dev/null || true;
/home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3/genext2fs -i 503 -b 1056 /
-d /home/skynet/build-tools/buildroot/build_i386/root -q -D target/default/device_table.txt /home/skynet/build-tools/buildroot/root_fs_i386.ext2
大功告成!!!
清点战利品
让我来看看它究竟做了哪些事情吧:
[root@skynet skynet]# cd tools
[root@skynet tools]# ls
bin bin-ccache i386-linux i386-linux-uclibc include info lib libexec man usr
bin:所有的编译工具,如gcc,都在这儿了,只是加了些指定的前缀;
bin-ccache:如果在Toolchain optaion中没有选择对ccache的支持,就没有这一项了;
i386-linux:链接文件;实际指向include
i386-linux-uclibc:uclibc的相关工具;
include:供交叉开发工具使用的头文件;
info:gcc 的info文件;
lib:供交叉开发工具使用的链接库文件;
……
现在可以把编译工具所在目录XXX/bin添加至PATH了
测试工具链
如果你现在写一个程序,用i386-linux-gcc来编译,运行的程序会告诉你:
./test: linked against GNU libc
因为程序运行库会寻到默认的/lib:/usr/lib上面去,而我们目前的uclibc的库并不在那里(虽然对于目标机来讲,这是没有错的),所以,也只能暂时静态编译,试试它能否工作了。当然,你也可以在建好根文件系统后,试试用chroot……
第三章 编译内核
本章的工作,是为目标机建立一个合适的内核,对于建立内核,我想有两点值得考虑的:
1、功能上的选择,应该能够满足需要的情况下,尽量地小;
2、小不是最终目的,稳定才是;
所以,最好编译内核前有一份目标机硬件平台清单以及所需功能清单,这样,才能更合理地裁减内核。
准备工具
Linux内核源码,我选用的是Linux-2.4.27.tar.bz2
编译内核
将Linux-2.4.27.tar.bz2拷贝至${PRJROOT}/kernel,解压
#cd linux-2.4.27
//配置
# make ARCH=i386 CROSS_COMPILE=i386-linux- menuconfig
//建立源码的依存关系
# make ARCH=i386 CROSS_COMPILE=i386-linux- clean dep
//建立内核映像
# make ARCH=i386 CROSS_COMPILE=i386-linux- bzImage
ARCH指明了硬件平台,CROSS_COMPILE指明了这是交叉编译,且编译器的名称为i386-linux-XXX,这里没有为编译器指明路径,是因为我前面已将其加入至环境变量PATH。
又是一个漫长的等待……
OK,编译完成,673K,稍微大了点,要移到其它平台,或许得想办法做到512以下才好,回头来想办法做这个工作。
安装内核
内核编译好后,将内核及配置文件拷贝至${PRJROOT}/images下。
# cp arch/i386/boot/bzImage ${PRJROOT}/images/bzImage-2.4.27-rmk5
# cp vmlinux ${PRJROOT}/images/vmlinux-2.4.27-rmk5
# cp System.map ${PRJROOT}/images/System-2.4.27-rmk5
# cp .config ${PRJROOT}/images/2.4.27-rmk5
我采用了后缀名的方式重命名,以便管理多个不同版本的内核,当然,你也可以不用这样,单独为每个版本的内核在images下新建对应文件夹也是可行的。
安装内核模块
完整内核的编译后,剩下的工作就是建立及安装模块了,因为我的内核并没有选择模块的支持(这样扩展性差了一点,但是对于我的系统来说,功能基本上定死了,这样影响也不太大),所以,剩下的步骤也省去了,如果你还需要模块的支持,应该:
//建立模块
#make ARCH=i386 CROSS_COMPILE=i386-linux- modules
//安装内核模块至${PRJROOT}/images
#make ARCH=i386 CROSS_COMPILE= i386-linux- /
>;INSTALL_MOD_PATH=${PRJROOT}/images/modules-2.4.18-rmk5 /
>;modules_install
最后一步是为模块建立依存关系,不能使用原生的depmod来建立,而需要使用交叉编译工具。需要用到busybox中的depmod.pl脚本,很可惜,我在busybox1.0.0中,并没有找到这个脚本,所以,还是借用了busybox0.63中scripts中的depmod.pl。
将depmod.pl拷贝至${PREFIX}/bin目录中,也就是交叉编译工具链的bin目录。
#depmod.pl /
>;-k ./vmlinux –F ./System.map /
>;-b ${PRJROOT}/images/modules-2.4.27-rmk5/lib/modules >; /
>;${PRJROOT}/images/modules-2.4.27-rmk5/lib/modules/2.4.27-rmk5/modules.dep
注:后面讨论移植内核和模块内容时,我只会提到内核的拷贝,因为我的系统并没有模块的支持。如果你需要使用模块,只需按相同方法将其拷贝至相应目录即可。
附,内核编译清单
附,内核选择:
内核编译记录:
Code maturity level options 不选
Loadable module support 不选
Processor type and features 根据实际,选择处理器类型
General setup --->;
Networking support
PCI support
(Any) CI access mode
PCI device name database
System V IPC
Sysctl support
(ELF) Kernel core (/proc/kcore) format
Kernel support for ELF binaries
Power Management support
Memory Technology Devices (MTD) --->; MTD设备,我用CF卡,不选
Parallel port support --->; 不选
Plug and Play configuration --->; 我的系统用不着即插即用,不选
Block devices --->;
Loopback device support
RAM disk support
(4096) Default RAM disk size (NEW)
Initial RAM disk (initrd) support
Multi-device support (RAID and LVM) --->; 不选
Networking options --->; 基本上都选了
ATA/IDE/MFM/RLL support --->; 用了默认的
Telephony Support --->; 不选
SCSI support --->; 不选
Fusion MPT device support --->; 不选
I2O device support --->; 不选
Network device support --->; 根据实际情况选择
Amateur Radio support --->; 不选
IrDA (infrared) support --->; 不选
ISDN subsystem --->; 不选
Old CD-ROM drivers (not SCSI, not IDE) --->; 不选
Input core support --->; 不选
Character devices --->;
Virtual terminal
Support for console on virtual terminal
Standard/generic (8250/16550 and compatible UARTs) serial support
Support for console on serial port
Multimedia devices --->; 不选
File systems --->;
Kernel automounter version 4 support (also supports v3)
Virtual memory file system support (former shm fs)
/proc file system support
Second extended fs support
Console drivers --->;
VGA text console 调试时接显示器用
剩下三个都不要
Sound --->;
USB support --->;
Kernel hacking --->;
第四章 建立根文件系统
1、建立目录
构建工作空间时,rootfs文件夹用来存放根文件系统,
#cd rootfs
根据根文件系统的基本结构,建立各个对应的目录:
# mkdir bin dev etc lib proc sbin tmp usr var root home
# chmod 1777 tmp
# mkdir usr/bin usr/lib usr/sbin
# ls
dev etc lib proc sbin tmp usr var
# mkdir var/lib var/lock var/log var/run var/tmp
# chmod 1777 var/tmp
对于单用户系统来说,root和home并不是必须的。
准备好根文件系统的骨架后,把前面建立的文件安装到对应的目录中去。
2、拷贝链接库
把uclibc的库文件拷贝到刚才建立的lib文件夹中:
# cd ${PREFIX}/lib
[root@skynet lib]# cp *-*.so ${PRJROOT}/rootfs/lib
[root@skynet lib]# cp -d *.so.[*0-9] ${PRJROOT}/rootfs/lib
3、 拷贝内核映像和内核模块
因为没有模块,所以拷贝模块就省了,
新建boot目录,把刚才建立好的内核拷贝过来
# cd /home/kendo/control-project/daq-module/rootfs/
# mkdir boot
# cd ${PRJROOT}/images
# cp bzImages-2.4.18-rmk5 /home/kendo/control-project/daq-module/rootfs/boot
4、 建立/dev下边的设备文件
在linux中,所有的的设备文件都存放在/dev中,使用mknod命令创建基本的设备文件。
mknod命令需要root权限,不过偶本身就是用的root用户,本来是新建了一个用户专门用于嵌入式制作的,不过后来忘记用了……
# mknod -m 600 mem c 1 1
# mknod -m 666 null c 1 3
# mknod -m 666 zero c 1 5
# mknod -m 644 random c 1 8
# mknod -m 600 tty0 c 4 0
# mknod -m 600 tty1 c 4 1
# mknod -m 600 ttyS0 c 4 64
# mknod -m 666 tty c 5 0
# mknod -m 600 console c 5 1
基本的设备文件建立好后,再创建必要的符号链接:
# ln -s /proc/self/fd fd
# ln -s fd/0 stdin
# ln -s fd/1 stdout
# ln -s fd/2 stderr
# ls
console fd mem null random stderr stdin stdout tty tty0 tty1 ttyS0 zero
设备文件也可以不用手动创建,听说RedHat /dev下的脚本MAKEDEV 可以实现这一功能,不过没有试过……
基本上差不多了,不过打算用硬盘/CF卡来做存储设备,还需要为它们建立相关文件,因为我的CF在目标机器上是CF-to-IDE,可以把它们等同来对待,先看看Redhat 下边had的相关属性:
# ls -l /dev/hda
brw-rw---- 1 root disk 3, 0 Jan 30 2003 /dev/hda
# ls -l /dev/hda1
brw-rw---- 1 root disk 3, 1 Jan 30 2003 /dev/hda1
对比一下,可以看出,had类型是b,即块设备,主编号为3,次编号从0递增,根限位是
rw-rw----,即660,所以:
# mknod -m 660 hda b 3 0
# mknod -m 660 hda1 b 3 1
# mknod -m 660 hda2 b 3 2
# mknod -m 660 hda3 b 3 3
5、添加基本的应用程序
未来系统的应用程序,基本上可以分为三类:
基本系统工具,如ls、ifconfig这些……
一些服务程序,管理工具,如WEB、Telnet……
自己开发的应用程序
这里先添加基本的系统工具,有想过把这些工具的代码下载下来交叉编译,不过实在是麻烦,用BusyBox,又精简又好用……
将busybox-1.00.tar.gz下载至sysapps目录下,解压:
#tar zxvf busybox-1.00.tar.gz
#cd busybox-1.00
//进入配置菜单
#make TARGET_ARCH=i386 CROSS=i386-linux- PREFIX=${PRJROOT}/rootfs menuconfig
//建立依存关系
#make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs dep
//编译
#make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs
//安装
#make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs install
# cd ${PRJROOT}/rootfs/bin
# ls
addgroup busybox chown delgroup echo kill ls mv ping rm sleep
adduser chgrp cp deluser grep ln mkdir netstat ps rmdir umount
ash chmod date dmesg hostname login mount pidof pwd sh vi
一下子多了这么多命令……
配置busybox的说明:
A、如果编译时选择了:
Runtime SUID/SGID configuration via /etc/busybox.conf
系统每次运行命令时,都会出现“Using fallback suid method ”
可以将它去掉,不过我还是在/etc为其建了一个文件busybox.conf搞定;
B、 Do you want to build BusyBox with a Cross Compiler? (i386-linux-gcc) Cross Compiler prefix
这个指明交叉编译器名称(其实在编译时的命令行已指定过了……)
C、安装选项下的(${PRJROOT}/rootfs) BusyBox installation prefix,这个指明了编译好后的工具的安装目录。
D、静态编译好还是动态编译好?即是否选择
[ ] Build BusyBox as a static binary (no shared libs)
动态编译的最大好处是节省了宝贵空间,一般来说都是用动态编译,不过我以前动态编译出过问题(其实是库的问题,不关busybox的事),出于惯性,我选择了静态编译,为此多付出了107KB的空间。
E、其它命令,根据需要,自行权衡。
6、系统初始化文件
内核启动时,最后一个初始化动作就是启动init程序,当然,大多数发行套件的Linux都使用了与System V init相仿的init,可以在网上下载System V init套件,下载下来交叉编译。另外,我也找到一篇写得非常不错的讲解如何编写初始化文件的文件,bsd-init,回头附在后面。不过,对于嵌入式系统来讲,BusyBox init可能更为合适,在第6步中选择命令的时候,应该把init编译进去。
#cd ${PRJROOT}/rootfs/etc
#vi inittab
我的inittal文件如下:
#指定初始化文件
::sysinit:/etc/init.d/rcS
#打开一个串口,波特率为9600
::respawn:/sbin/getty 9600 ttyS0
#启动时执行的shell
::respawn:/bin/sh
#重启时动作
::restart:/sbin/init
#关机时动作,卸载所有文件系统
::shutdown:/bin/umount -a –r
保存退出;
再来编写rcS脚本:
#mkdir ${PRJROOT}/rootfs/etc/init.d
#cd ${PRJROOT}/rootfs/etc/init.d
#vi rcS
我的脚本如下:
#!/bin/sh
#Set Path
PATH=/sbin:/bin
export PATH
syslogd -m 60
klogd
#install /proc
mount -n -t proc none /proc
#reinstall root file system by read/write mode(need: /etc/fstab)
mount -n -o remount,rw /
#reinstall /proc
mount -n -o remount,rw -t proc none /proc
#set lo ip address
ifconfig lo 127.0.0.1
#set eth0 ip address
#当然,这样子做只是权宜之计,最后做的应该是在这一步引导网络启动脚本,像RedHat
#那样,自动读取所有指定的配置文件来启动
ifconfig eth0 192.168.0.68 netmask 255.255.255.0
#set route
#同样的,最终这里应该是运行启动路由的脚本,读取路由配置文件
route add default gw 192.168.0.1
#还差一个运行服务程序的脚本,哪位有现成的么?
#网卡/路由/服务这三步,事实上可以合在一步,在rcS这一步中,做一个循环,运行指定启动目录下的所有脚,先将就着这么做吧,确保系统能够正常启动了,再来写这个脚本。
#set hostname
hostname MyLinux
保存退出。
编写fstab文件
#vi fstab
我的fstab很简单:
/dev/hda1 / ext2 defaults 1 1
none /proc proc defaults 0 0
第五章 让MyLinux能够启动
前一章,我们把编译好的内核、应用程序、配置文件都拷贝至rootfs目录对应的子目录中去了,这一步,就是把这些文件移植至目标机的存储器。这里,我是先另外拿一块硬盘,挂在我的开发机上做的测试,因为我的本本用来写文档,PC机用来做开发机,已经没有另外的机器了……但是本章只是讲述一个一般性的过程,并不影响你直接在目标主机上的工作。
因为以后目标机识别硬盘序号都是hda,而我现在直接挂上去,则会是hdb、hdc……这样,安装lilo时有点麻烦(虽然也可以实现)。所以我想了另一个办法:
把新硬盘挂在IDE0的primary上,进入linux后,会被认为是had;
原来主机的装Redhat的硬盘,我将它从IDE0的primary上变到了IDE1 的primary,因为它的lilo早已装好,基本上不影响系统的使用;
分区和格式化
BIOS中改为从第二个硬盘启动;也就是从我原来开发机启动,新的硬盘被识别成了had。
#fdisk /dev/hda
用d参数删除已存在的所有分区
用n参数新建一个分区,也是就/dev/hda1
格式化
#mkfs.ext2 /dev/hda1
安装bootloader
因为我是X86平台,所以直接用了lilo,如果你是其这平台,当然,有许多优秀的bootloader供你选择,你只需查看其相应的说明就可以了。
编译lilo配置文件,我的配置文件名为target.lilo.conf,置于${PRJROOT}/rootfs/etc目录。内容如下所示:
boot=/dev/hda
disk=/dev/hda
bios=0x80
image=/boot/bzImage-2.4.18-rmk5
label=Linux
root=/dev/hda1
append="root=/dev/hda1"
read-only
//新建文件夹,为mount做新准备
#mkdir /mnt/cf
//把目标硬盘mount上来
#mount –t ext2 /dev/hdc1 /mnt/cf
回到rootfs
#cd ${PRJROOT}/rootfs
拷贝所有文件至目标硬盘
#cp –r * /mnt/cf
这样,我们所有的文件都被安装至目标硬盘了,当然,它还不能引导,因为没有bootloader。使用如下命令:
# lilo -r /mnt/cf -C etc/target.lilo.conf
Warning: LBA32 addressing assumed
Added Linux *
-r :改变根目标为/mnt/cf ,这样配置文件其实就是/mnt/cf/etc/target.lilo.conf,也就是我们先前建立的文件。
当然,完成这一步,需要lilo22.3及以后版本,如果你的版本太旧,比如Redhat9.0自带的,就会出现下面的信息:
#lilo –r /mnt/cf –C etc/target.lilo.conf
Fatal: open /boot/boot.b: No such file or directory
这时,你需要升级你的lilo,或者重新安装一个。
启动系统
#umount /mnt/cf
#reboot
将BIOS改为从IDE0启动,也就是目标硬盘。如果一切顺利,你将顺利进入一个属于你的系统。
回头再来看看我们的工作空间吧
[root@skynet lib]# df /dev/hda1
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/hda1 3953036 1628 3750600 1% /mnt/cf
总共花去了我1628KB的空间,看来是没有办法放到软盘里边去了^o^,不过一味求小,并不是我的目标。
[root@skynet skynet]# ls ${PRJROOT}
bootloader build-tools debug doc images kernel rootfs sysapps tmp tools
这几个目录中的文件,呵呵,与本文一开头规划的一样
[root@skynet skynet]# ls build-tools/
buildroot buildroot-0.9.27.tar.tar
包含了buildroot源码及压缩包,事实上buildroot下边还包括了GNU其它工具的源码、编译文件等诸多内容,是我们最重要的一个文件夹,不过到现在它已经没有多大用处了,如果你喜欢,可以将它删除掉(不建议)。
[root@skynet skynet]# ls images
2.4.18-rmk5 bzImage-2.4.18-rmk5 System-2.4.18-rmk5 vmlinux-2.4.18-rmk5
内核映像及配置文件等,如果你有模块,因为还有相应的目录
[root@skynet skynet]# ls kernel/
linux-2.4.27 linux-2.4.27.tar.bz2
内核源码及压缩包
[root@skynet skynet]# ls rootfs/
bin boot dev etc home lib linuxrc proc root sbin tmp usr var
制作好的根文件系统,重中之重,注意备份……
[root@skynet skynet]# ls sysapps/
busybox-1.00 busybox-1.00.tar.gz
busybox-1.00源码包,或许你还要继续添加/删除一些命令……
[root@skynet skynet]# ls tools
bin i386-linux i386-linux-uclibc include info lib man
这个也很重要,我们制作好的交叉开发工具链。如果你要继续开发程序,这个目录重要性就很高了。
其它目录暂时是空的。
第六章 完善MyLinux
关于进一步的调试,你可以在开发机上使用chroot /mnt/cf /bin/sh这样的命令,以使我们在目标根文件系统上工作。
支持多用户
因为我在编译busybox时,已经将它的多用户那一大堆命令编译了进来。现在关键是的要为其建立相应的文件;
进入原来的开发机,进入rootfs目录,切换根目录
#chroot rootfs/ /bin/sh
A、 建立/etc/passwd文件,我的文件内容如下:
root:x:0:0:root:/root:/bin/bash
B、 建立/etc/group文件,我的文件内容如下:
root:x:0:
bin:x:1:
sys:x:2:
kmem:x:3:
tty:x:4:
tape:x:5:
daemon:x:6:
disk:x:7:
C、 为root建立密码
#passwd root
试试用addgroup/addusr……这堆命令。然后重启,从目标硬盘上启动;从console口,9600登陆试试(因为我在inittab中启用了ttyS0,我未来的目标机,是没有显卡的,需要从console口或SSH进去管理)
MyLinux login: root
Password:
BusyBox v1.00 (2004.10.10-04:43+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.
~ #
成功了……
增加WEB Server
Busybox里边有httpd选项,不过我编译时并没有选择,所以还是自己来安装。我使用的软件是thttpd-2.25b.tar.gz,将它移至sysapps目录下。
[root@skynet sysapps]# tar zxvf thttpd-2.25b.tar.gz
[root@skynet sysapps]# cd thttpd-2.25b
//配置
[root@skynet thttpd-2.25b]# CC=i386-linux-gcc ./configure --host=$TARGET
……
i386-linux-gcc -static htpasswd.o -o htpasswd -lcrypt
make[1]: warning: Clock skew detected. Your build may be incomplete.
make[1]: Leaving directory `/home/skynet/sysapps/thttpd-2.25b/extras'
//拷贝至根文件目录
[root@skynet thttpd-2.25b]# cp thttpd ${PRJROOT}/rootfs/usr/sbin
//trip处理
[root@skynet thttpd-2.25b]# i386-linux-strip ${PRJROOT}/rootfs/usr/sbin/thttpd
剩下的,就发挥各人的想像吧……
[ 本帖最后由 platinum 于 2005-11-9 09:03 编辑 ]
PDF版本及后续PDF更新版本,你可以在
http://www.skynet.org.cn/viewthread.php?tid=82
下载。
不过好像下载要先注册(我没找到如何取消这一限制)!
1.准备:
下载2.6内核linux-2.6.2-rc2.tar.gz
http://www.kernel.org/pub/linux/kernel/v2.6/testing/linux-2.6.2-rc2.tar.gz
不需要下载http://www.kernel.org/pub/linux/kernel/v2.6/testing/patch-2.6.2-rc2.gz
这个补丁是给以前的内核版本升级到2.6.2-rc2用的
2.本人系统为redhat8.0
解压到目录/usr/src
#cp linux-2.6.2-rc2.tar.gz /usr/src
#cd /usr/src
#tar -zxvf linux-2.6.2-rc2.tar.gz
建立链接文件
#cd /usr/src
#ln –s linux-2.6.2-rc2 linux-2.6
#ln –s linux-2.6 linux
检查原代码
#cd /usr/src/linux
#make mrproper
这步是为确保原代码目录下没有不正确的.o文件及文件的相互依赖。
配置核心选项
#make menuconfig
基本上保持默认选项就可以了,但是要注意的是必须把ext2和ext3文件系统支持编进内核,否则升级内核重新启动是会有错误:
Kernel panic: No init found. Try passing init= option to kernel
ext2和ext3文件系统配置为:
File systems -
; Second extended fs support
Ext2 extended attributes
Ext2 POSIX Access Control Lists
Ext2 Security Labels
; Ext3 journalling file system support
Ext3 extended attributes
Ext3 POSIX Access Control Lists
Ext3 Security Labels
JBB (ext3) debugging support
编译内核
确保所有文件都处于最新的版本状态下
#make clean
编译模块
#make modules
安装模块
#make modules_install
此时在/lib/modules下出现新内核模块文件夹2.6.2-rc2
使用新内核
#cp System.map /boot/System.map-2.6.2-rc2
#rm /boot/System.map
#ln –s /boot/System.map-2.6.2-rc2 /boot/System.map
#cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.2-rc2
#rm /boot/vmlinuz
#ln –s /boot/vmlinuz-2.6.2-rc2 /boot/vmlinuz
#new-kernel-pkg –install –mkinitrd –depmod 2.6.2-rc2
执行完new-kernel-pkg命令后在/boot下生成新印象文件initrd-2.6.2-rc2,同时/etc/grub.conf中增加了新核心的启动项,
例如:
Tilte linux (2.6.20-rc2)
Root(hd0,0)
Kernel /boot/vmlinuz-2.6.2-rc2 ro root=LABEL=/
Initrd /boot/initrd-2.6.2-rc2
将kernel项中的root=LABEL=/ 改成 root=/dev/hda7 (/dev/hda7是本人linux的根分区),否则重启动后会有错误:
Kernel panic: No init found. Try passing init= option to kernel
#reboot
重启后Grub中出现2.6内核的启动项,现在就用新的核心试试吧。
国庆快到了,送给大家一篇文章作礼物吧,也作为在chinaunix这个大家庭中我曾得到过许多热心朋友的大力支持的回报,下文是我工作中总结的文档,有些核心参数的调节是为安装oracle数据库而使用,无此方面应用的朋友可以跳过。
欢迎转载,但请注明出处。
一、备份重要文件
备份以下这些文件可以在系统发生错误或崩溃时,能较快速的恢复系统原来的状态。
1、备份内核和启动文件
# cd /
# tar cvzf boot.tar.gz boot
2、备份系统函数头文件
# cd /usr/include
# tar cvzf linux.tar.gz linux
3、备份模块中的库文件
# cd /lib/modules
# tar cvzf 2.4.7-10.tar.gz 2.4.7-10
# tar cvzf 2.4.7-10debug.tar.gz 2.4.7-10debug
4、备份linux源码
# cd /usr/src
# tar cvzf linux-2.4.7-10.tar.gz linux-2.4.7-10
# tar cvzf linux-2.4.7-10debug.tar.gz linux-2.4.7-10debug
5、备份重要配置目录
# cd /
# tar cvzf etc.tar.gz etc
二、修改核心参数(PGC2000需要)
1、修改与共享内存相关的核心参数
# cd /usr/include/linux
# vi shm.h
把 #define SHMMAX 0X2000000 /*max shared seg size(bytes)*/
改为#define SHMMAX 0Xa0000000 /*max shared seg size(bytes)*/
2、修改与信号量相关的核心参数
# cd /usr/include/linux
# vi sem.h
把 #define SEMOPM 32 /*
改为#define SEMOPM 900 /*
3、修改与消息队列有关的核心参数
# cd /usr/include/linux
# vi msg.h
找到以下三行(注释忽略):
#define MSGMNI 16
#define MSGMAX 8192
#define MSGMNB 16384
将其修改为:
#define MSGMNI 128
#define MSGMAX 131072
#define MSGMNB 20000000
4、按上面方法同样修改/usr/src/linux-2.4.7-10/include/linux下的shm.h、sem.h和msg.h文件。
三、下载释放核心源代码
如果只是修改编译内核,这一步可以省去。当我们从Internet站点上下载了新的内核文件(如linux-2.4.7-12.tar.gz),这步是必须的。
1、用tar命令释放内核源代码
# cd /usr/src
# tar zxvf linux-2.4.7-12.tar.gz
文件释放成功后,在/usr/src目录下会生成一个linux子目录。其中包括了源代码。
2、将/usr/include/asm、/usr/inlude/linux、/usr/include/scsi链接到/usr/src/linux/include目录下的对应目录中。
# cd /usr/include
# rm -Rf asm linux
# ln -s /usr/src/linux/include/asm-i386 asm
# ln -s /usr/src/linux/include/linux linux
# ln -s /usr/src/linux/include/scsi scsi
四、配置内核
1、删除源代码目录中残留的.o文件和其它从属文件。
# cd /usr/src/linux-2.4
# make mrproper
2、启动内核配置程序
# cd /usr/src/linux-2.4
# make xconfig
3、配置内核
Linux的内核配置程序提供了一系列配置选项。对于每一个配置选项,用户可以回答"y"、"m"或"n"。其中"y"表示将相应特性的支持或设备驱动程序编译进内核;"m"表示将相应特性的支持或设备驱动程序编译成可加载模块,在需要时,可由系统或用户自行加入到内核中去;"n"表示内核不提供相应特性或驱动程序的支持。不合理的配置可能造成内核编译失败。
五、编译内核
1、建立编译时所需的从属文件
# cd /usr/src/linux-2.4
# make dep
2、清除内核编译的目标文件
# make clean
3、编译内核
# make bzImage (注意大小写)
内核编译成功后,会在/usr/src/linux/arch/i386/boot目录中生成一个新内核的映像文件bzImage。如果用make zImage编译,内核很大的话,系统会提示你使用make bzImage命令来编译。
六、编译可加载模块
如果用户在配置内核时设置了可加载模块,则需要对这些模块进行编译,以便将来使用insmod命令进行加载。
# make modules
# make modules_install
编译成功后,系统会在/lib/modules目录下生成一个2.4.7-10custom子目录,里面存放着新内核的所有可加载模块。
七、启动新内核
1、将新内核和System.map文件拷贝到/boot目录下
# cp /usr/src/linux-2.4/arch/i386/boot/bzImage /boot/vmlinuz-2.4.7-10custom
# cp /usr/src/linux-2.4/System.map /boot/System.map-2.4.7-10custom
# cd /boot
# rm -f System.map (删除原来的连接)
# ln -s System.map-2.4.7-10custom System.map (重新建立连接)
2、配置/etc/lilo.conf文件,在该文件中加入下面几行:
image=/boot/vmlinuz-2.4.7-10custom
label=linux-custom
initrd=/boot/initrd-2.4.7-10.img
read-only
root=/dev/hda3 (参考lilo.conf文件中现有的配置)
并把default=linux改为default=linux-custom
3、使新配置生效
# /sbin/lilo
4、重新启动系统
# /sbin/reboot
新内核如果不能正常启动,可以在LILO:提示符下启动旧内核。然后查出故障原因,重新编译新内核即可。
__________________________________
知识是经验的积累,才能是刻苦的忍耐。
针对好多Linux 爱好者对内核很有兴趣却无从下口,本文旨在介绍一种解读linux内核源码的入门方法,而不是解说linux复杂的内核机制;
一.核心源程序的文件组织:
1.Linux核心源程序通常都安装在/usr/src/linux下,而且它有一个非常简单的编号约定:任何偶数的核心(例如2.0.30)都是一个稳定地发行的核心,而任何奇数的核心(例如2.1.42)都是一个开发中的核心。本文基于稳定的2.2.5源代码,第二部分的实现平台为 Redhat Linux 6.0。
2.核心源程序的文件按树形结构进行组织,在源程序树的最上层你会看到这样一些目录:
●Arch :arch子目录包括了所有和体系结构相关的核心代码。它的每一个子目录都代表一种支持的体系结构,例如i386就是关于intel cpu及与之相兼容体系结构的子目录。PC机一般都基于此目录;
●Include: include子目录包括编译核心所需要的大部分头文件。与平台无关的头文件在 include/linux
子目录下,与 intel cpu相关的头文件在include/asm-i386子目录下,而include/scsi目录则是有关 scsi设备的头文件目录;
●Init: 这个目录包含核心的初始化代码(注:不是系统的引导代码),包含两个文件main.c和Version.c,这是研究核心如何工作的一个非常好的起点。
●Mm :这个目录包括所有独立于 cpu 体系结构的内存管理代码,如页式存储管理内存的分配和释放等;而和体系结构相关的内存管理代码则位于arch/*/mm/,例如arch/i386/mm/Fault.c
●Kernel:主要的核心代码,此目录下的文件实现了大多数linux系统的内核函数,其中最重要的文件当属 sched.c;同样,和体系结构相关的代码在arch/*/kernel中;
●Drivers: 放置系统所有的设备驱动程序;每种驱动程序又各占用一个子目录:如,/block 下为块设备驱动程序,比如ide(ide.c)。如果你希望查看所有可能包含文件系统的设备是如何初始化的,你可以看drivers/block/genhd.c中的device_setup()。它不仅初始化硬盘,也初始化网络,因为安装nfs文件系统的时候需要网络其他: 如, Lib放置核心的库代码; Net,核心与网络相关的代码; Ipc,这个目录包含核心的进程间通讯的代码; Fs ,所有的文件系统代码和各种类型的文件操作代码,它的每一个子目录支持一个文件系统,例如fat和ext2; Scripts, 此目录包含用于配置核心的脚本文件等。一般,在每个目录下,都有一个 .depend 文件和一个 Makefile 文件,这两个文件都是编译时使用的辅助文件,仔细阅读这两个文件对弄清各个文件这间的联系和依托关系很有帮助;而且,在有的目录下还有Readme 文件,它是对该目录下的文件的一些说明,同样有利于我们对内核源码的理解;
二.解读实战:为你的内核增加一个系统调用
虽然,Linux 的内核源码用树形结构组织得非常合理、科学,把功能相关联的文件都放在同一个子目录下,这样使得程序更具可读性。然而,Linux 的内核源码实在是太大而且非常复杂,即便采用了很合理的文件组织方法,在不同目录下的文件之间还是有很多的关联,分析核心的一部分代码通常会要查看其它的几个相关的文件,而且可能这些文件还不在同一个子目录下。体系的庞大复杂和文件之间关联的错综复杂,可能就是很多人对其望而生畏的主要原因。当然,这种令人生畏的劳动所带来的回报也是非常令人着迷的:你不仅可以从中学到很多的计算机的底层的知识(如下面将讲到的系统的引导),体会到整个操作系统体系结构的精妙和在解决某个具体细节问题时,算法的巧妙;而且更重要的是:在源码的分析过程中,你就会被一点一点地、潜移默化地专业化;甚至,只要分析十分之一的代码后,你就会深刻地体会到,什么样的代码才是一个专业的程序员写的,什么样的代码是一个业余爱好者写的。
为了使读者能更好的体会到这一特点,下面举了一个具体的内核分析实例,希望能通过这个实例,使读者对 Linux的内核的组织有些具体的认识,从中读者也可以学到一些对内核的分析方法。
以下即为分析实例:
【一】操作平台:
硬件:cpu intel Pentium II ;
软件:Redhat Linux 6.0; 内核版本2.2.5
【二】相关内核源代码分析:
1.系统的引导和初始化:Linux 系统的引导有好几种方式:常见的有 Lilo, Loadin引导和Linux的自举引导(bootsect-loader),而后者所对应源程序为arch/i386/boot/bootsect.S,它为实模式的汇编程序,限于篇幅在此不做分析;无论是哪种引导方式,最后都要跳转到 arch/i386/Kernel/setup.S, setup.S主要是进行时模式下的初始化,为系统进入保护模式做准备;此后,系统执行 arch/i386/kernel/head.S (对经压缩后存放的内核要先执行 arch/i386/boot/compressed/head.S); head.S 中定义的一段汇编程序setup_idt ,它负责建立一张256项的 idt 表(Interrupt Descriptor Table),此表保存着所有自陷和中断的入口地址;其中包括系统调用总控程序 system_call 的入口地址;当然,除此之外,head.S还要做一些其他的初始化工作;
2.系统初始化后运行的第一个内核程序asmlinkage void __init start_kernel(void) 定义在 /usr/src/linux/init/main.c中,它通过调用usr/src/linux/arch/i386/kernel/traps.c 中的一个函数 void __init trap_init(void) 把各自陷和中断服务程序的入口地址设置到 idt 表中,其中系统调用总控程序 system_cal就是中断服务程序之一;void __init trap_init(void) 函数则通过调用一个宏 set_system_gate(SYSCALL_VECTOR,&system_call); 把系统调用总控程序的入口挂在中断0x80上; 其中SYSCALL_VECTOR是定义在 /usr/src/linux/arch/i386/kernel/irq.h中的一个常量0x80; 而 system_call 即为中断总控程序的入口地址;中断总控程序用汇编语言定义在/usr/src/linux/arch/i386/kernel/entry.S中;
3.中断总控程序主要负责保存处理机执行系统调用前的状态,检验当前调用是否合法, 并根据系统调用向量,使处理机跳转到保存在 sys_call_table 表中的相应系统服务例程的入口; 从系统服务例程返回后恢复处理机状态退回用户程序; 而系统调用向量则定义在/usr/src/linux/include/asm-386/unistd.h 中;sys_call_table 表定义在 /usr/src/linux/arch/i386 kernel/entry.S 中; 同时在 /usr/src/linux/include/asm-386/unistd.h 中也定义了系统调用的用户编程接口;
4.由此可见 , linux 的系统调用也象 dos 系统的 int 21h 中断服务, 它把0x80 中断作为总的入口, 然后转到保存在 sys_call_table 表中的各种中断服务例程的入口地址 , 形成各种不同的中断服务; 由以上源代码分析可知, 要增加一个系统调用就必须在 sys_call_table 表中增加一项 , 并在其中保存好自己的系统服务例程的入口地址,然后重新编译内核,当然,系统服务例程是必不可少的。 由此可知在此版linux内核源程序;中,与系统调用相关的源程序文件就包括以下这些:
1.arch/i386/boot/bootsect.S
2.arch/i386/Kernel/setup.S
3.arch/i386/boot/compressed/head.S
4.arch/i386/kernel/head.S
5.init/main.c
6.arch/i386/kernel/traps.c
7.arch/i386/kernel/entry.S
8.arch/i386/kernel/irq.h
9.include/asm-386/unistd.h
当然,这只是涉及到的几个主要文件。而事实上,增加系统调用真正要修改文件只有include/asm-386/unistd.h
和arch/i386/kernel/entry.S两个;
【三】 对内核源码的修改:
1.在kernel/sys.c中增加系统服务例程如下:
asmlinkage int sys_addtotal(int numdata)
{
int i=0,enddata=0;
while(i
enddata+=i++;
return enddata;
}
该函数有一个 int 型入口参数 numdata , 并返回从 0 到 numdata 的累加值; 当然也可以把系统服务例程放在一个自己定义的文件或其他文件中,只是要在相应文件中作必要的说明;
2.把 asmlinkage int sys_addtotal( int) 的入口地址加到sys_call_table表中:
arch/i386/kernel/entry.S 中的最后几行源代码修改前为:
... ...
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
.rept NR_syscalls-190
.long SYMBOL_NAME(sys_ni_syscall)
.endr
修改后为: ... ...
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
/* add by I */
.long SYMBOL_NAME(sys_addtotal)
.rept NR_syscalls-191
.long SYMBOL_NAME(sys_ni_syscall)
.endr
3. 把增加的 sys_call_table 表项所对应的向量,在include/asm-386/unistd.h 中进行必要申明,以供用户进程和其他系统进程查询或调用:
增加后的部分 /usr/src/linux/include/asm-386/unistd.h 文件如下:
... ...
#define __NR_sendfile 187
#define __NR_getpmsg 188
#define __NR_putpmsg 189
#define __NR_vfork 190
/* add by I */
#define __NR_addtotal 191
4.测试程序(test.c)如下:
#include
#include
_syscall1(int,addtotal,int, num)
main()
{
int i,j;
do
printf("lease input a number/n"
while(scanf("%d",&i)==EOF);
if((j=addtotal(i))==-1)
printf("Error occurred in syscall-addtotal();/n"
printf("Total from 0 to %d is %d /n",i,j);
}
对修改后的新的内核进行编译,并引导它作为新的操作系统,运行几个程序后可以发现一切正常;在新的系统下对测试程序进行编译(*注:由于原内核并未提供此系统调用,所以只有在编译后的新内核下,此测试程序才能可能被编译通过),运行情况如下:
$gcc -o test test.c
$./test
Please input a number
36
Total from 0 to 36 is 666
可见,修改成功;
而且,对相关源码的进一步分析可知,在此版本的内核中,/usr/src/linux/arch/i386/kernel/entry.S
文件中对 sys_call_table 表的设置可以看出,有好几个系统调用的服务例程都是定义在
/usr/src/linux/kernel/sys.c 中的同一个函数:
asmlinkage int sys_ni_syscall(void)
{
return -ENOSYS;
}
例如第188项和第189项就是如此:
... ...
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
... ...
而这两项在文件 /usr/src/linux/include/asm-386/unistd.h 中却申明如下:
... ...
#define __NR_sendfile 187
#define __NR_getpmsg 188 /* some people actually want streams */
#define __NR_putpmsg 189 /* some people actually want streams */
#define __NR_vfork 190
由此可见,在此版本的内核源代码中,由于asmlinkage int sys_ni_syscall(void) 函数并不进行任何操作, 所以包括 getpmsg, putpmsg 在内的好几个系统调用都是不进行任何操作的,即有待扩充的空调用; 但它们却仍然占用着sys_call_table表项,估计这是设计者们为了方便扩充系统调用而安排的; 所以只需增加相应服务例程(如增加服务例程getmsg或putpmsg),就可以达到增加系统调用的作用。
结语:当然对于庞大复杂的 linux 内核而言,一篇文章远远不够,而且与系统调用相关的代码也只是内核中极其微小的一部分;但重要的是方法、掌握好的分析方法;所以上的分析只是起个引导的作用,而正真的分析还有待于 读者自己的努力。
__________________________________
我是一只小小鸟,想要飞,却怎么也飞不高!
广交天下Linux朋友(只谈技术)
QQ:19554497
E-mail:[url=mailto:[email protected]][email protected][/url]
转自:
http://tech.ccidnet.com/art/322/20060321/485291_1.html
1。我个人认为作者MAX对Linux的了解不像他对Solaris那样深入,我不知道也没法知道他的下列关于Linux的内容来自自己的代码阅读分析还是只是来自第三方的文档资料而未经自己实地验证;
2。我已经尽量符合原意地翻译了,当然中间实在忍不住的地方也插两句自己的话;
3。无论是只阅读这一篇文章,还是看其他东西,我都觉得,保持自己头脑清醒很重要;
4。谢谢
Max Bruning 是一名教师/资讯专家,他的教授内容包括Solaris内部组织,设备驱动,内核和应用的crash分析及调试,网络组织和其他一些特定科目(他的 blog在blogspot,不费点劲可能访问不了,所以也可以看看www.bruningsystems.com)。
在解释这些子系统在Solaris中是如何实现的时候,他的学生们总会问“Linux里它是怎么工作的?”或者“FreeBSD里是这样,Solaris里呢?”这种经历最终让Max在OpenSolaris网站写了这篇A Comparison of Solaris, Linux, and FreeBSD Kernels。
文章里讨论了调度,内存管理和文件系统架构--这3个子系统在任何操作系统中都有普遍应用,而且他们是最well-understood 的组件。
目前很多分析或对比文章所引用的材料及代码都比较老,与现实脱节,Max推荐如下几个多少比较up to date的网站:
Solaris Vs. Linux
Comparing MySQL Performance
Fast Track to Solaris 10 Adoption
Solaris 10 Heads for Linux Territory
其实抛开3个系统之间的差别,他们也有很多相似之处。除了那些不同的命名习惯,这些OS在实现不同概念的时候采用了非常相似的方法。他们都支持线程的分时调度,支持最近未使用页面替换算法实现请求调页,支持虚拟文件系统层允许不同文件系统架构。这个系统里的一个好概念在另一个系统里也会采用。比如 Linux也接受并实现了 Solaris slab 内存分配算法的概念。FreeBSD 代码里的很多术语在Solaris里也出现了(快去看看代码。。。)。考虑到这3个系统的源代码都能得到了, fxr.watson.org提供了系统源码的交叉阅读浏览,可能会发现很多有趣的地方。
好了,温情默默的套近乎结束,进入正题。
调度和调度器
Solaris的调度单位是kthread_t,FreeBSd是thread,Linux是task_struct。抬高一级,Solaris的进程是proc_t,当然每个进程里的线程就是kthread_t;Linux的进程和线程都由task_struct 表示,单线程的进程在Linux里是一个task_struct。单线程的进程在Solaris里有一个proc_t,一个kthread_t,还有一个klwp_t表示。klwp_t提供了用户和内核模式线程切换的存储区。FreeBSD里的单线程进程有一个proc ,一个thread 和一个ksegrp 。ksegrp 是“内核调度的实体组kernel scheduling entity group”。三个系统的线程表示结构不同,不过都支持调度线程。
和大家熟悉的基本一样,调度是基于优先级的。小小的数学问题是,在Linux和FreeBSD里,数字越小,优先级越高;而SUN的宝贝却喜欢数字越大,优先级越高。参考下表
图片附件: schedule.png (2006-7-1 23:20, 17.07 K)
screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='点击在新窗口查看全图/nCTRL+鼠标滚轮放大或缩小';}" onmousewheel="return imgzoom(this);">
三个系统都更推崇interactive 线程/进程(下面会提到interactive怎么回事)。Interactive 线程比compute-bound 线程优先级要高,不过得到的时间片要少一些。Solaris,FreeBSD和Linux都使用每CPU的“运行队列 runqueue”。FreeBSD和Linux有一个active队列和一个expired队列。名字说得很清楚了--系统从active上按照优先级选择线程进行调度。用完自己时间片的线程就从active搬到expired上(或者为了避免“饿死”的其他情况),active空以后,内核交换 active和expired。FreeBSD还多一个idle 队列--其他两个queue都空的时候才轮到这个。Solaris的概念是每CPU“调度队列 dispatch queue”。线程用完时间片后,内核给其一个新优先级然后放回调度队列。所有3个系统的runqueue,对不同优先级的可运行线程都分别有链表。
FreeBSD四个优先级共享一个链表,Solaris和Linux则每个优先级一个链表Linux和FreeBSD结合运行时间和睡眠时间计算线程的 interactive-ness,Solaris查表。他们都不支持“gang scheduling”(有兴趣查Google即知,并行计算上的调度算法,大白话说就是一组任务一把disptach到各个CPU上。劳伦斯.利弗莫尔那帮造原子弹的家伙最喜欢了,他们有世界上最昂贵的玩具,可以理解)每个OS都调度下一个线程而不是N个线程开始运行。这3个OS都有利用CACHE (warm affinity)和负载均衡的机制。对超线程CPU,FreeBSD能尽量将多个线程保持在一个CPU节点上(当然可能是不同的CPU超线程上)。 Solaris也有类似机制,不过是在用户和应用的控制下,而且并不限于CPU的超线程,他们的术语是processor sets,FreeBSD的叫法是processor groups和其他2个OS最大的不同是,Solaris同时支持多个“scheduling classes”。3个OS都支持POSIX的SCHED_FIFO,SCHED_RR和SCHED_OTHER (或者SCHED_NORMAL)。SCHED_FIFO 和SCHED_RR通常支持实时线程(我不同意。。。但是照翻。。。)。
[ 本帖最后由 compnik 于 2006-7-1 23:25 编辑 ]
Solaris和Linux为支持实时线程都支持了内核抢占。Solaris支持fixed priority类,system class的是系统线程(比如换页线程),interactive的是在X控制下运行窗口环境的线程,还有一个Fair Share Scheduler 用于资源管理。具体可以参考Solaris资料。FreeBSD的调度器是在编译时决定的,Linux的调度?--要看版本了。
支持在系统中加入新的调度类是要付出代价的。内核中每个可能决定调度的地方都得有一个间接得函数调用去call调度类相关的代码。比如,当一个线程将要 sleep时,内核调用调度类相关代码,完成该类中线程sleep需要完成工作。在Linux和FreeBSD上,调度已经完成了所有工作。不需要再来一个间接调用。额外的层次,就意味着Solaris的调度要占用稍微多一点的系统开销--不过提供了更多的功能。
内存管理和分页
Solaris的进程地址空间由逻辑段segment组成。进程地址中的这些段可以通过pmap访问。Solaris将其内存管理代码和数据结构分为平台无关和平台相关部分(这不跟没说一样嘛。。。)。平台相关部分位于HAT(hardware address translation)层。FreeBSD用vmspace描述进程地址空间,将其划分为逻辑块region。硬件相关部分在pmap (physical map)模块,而vmap 例程处理硬件无关部分和数据结构。Linux使用内存描述符划分进程地址空间,逻辑单位是memory areas。Linux也由pmap来examine 进程地址空间。
Linux将机器相关层从更高层次的机器无关层中划分出来。Solaris 和FreeBSD中大多数类似代码比如page fault处理是机器无关的,而Linux处理page fault的代码则非常机器相关--从fault处理开始就是这样了。由此下来的结果是,Linux能很快地完成大多数分页相关代码--因为数据抽象更少。不过,代价是,下层硬件的改变需要大量修改代码--Solaris和FreeBSD则分别把这样的工作堵截在HAT和pmap层搞定。
Segment,region和meory area的分割是:区域的虚拟地址segmetn/region/memory area映射的object/文件的位置权限map的大小
例如,程序的text(text段,即代码)在一个segmetn/region/memory area中,OS管理地址空间的机制是类似的,不过数据结构名字完全不同。
分页3个系统都使用了最近最少使用least recently used算法的变种完成页替换。他们都有一个守护daemon进程/线程完成页替换。FreeBSD的是vm_pageout daemon,它周期性地,或者当free的内存不多时,被唤醒。当可用内存低于某个限制时,vm_pageout 运行例程vm_pageout_scan扫描内存并释放一些页面。vm_pageout_scan例程可能需要异步地将更改过的页面写回到磁盘,在释放他们之前。不论由多少颗CPU,只有一个这样的daemon。Solaris的是pageout daemon,它也周期性地运行,处理空闲内存不多的情况。Solaris中的分页限制值在系统启动时自动校准,这样可以避免该守护进程过渡占用CPU或者向磁盘发出洪水般的换页请求(嗯,flood这么翻正好 ; P )。
FreeBSD的daemon在大多数情况下使用的值是固定的--不过也可以调整。Linux的LRU算法可以在运行时动态调整,而且可以有多个kswapd daemon,每CPU最多一个。这3个系统都使用global working set策略,而不是per process working set。FreeBSD有多个页面链表来追踪最近使用页。包括active,inactive,cached和feee页。根据使用情况,页面在这些链表间走来走去。经常访问的页面会在active上。退出的进程的数据页面将被马上放到free上。
[ 本帖最后由 compnik 于 2006-7-1 23:26 编辑 ]
如果因为负载原因vm_pageout_scan 来不及扫描全部内存的话,FreeBSD内核可能将整个进程全部换出。如果内存短缺十分严重,vm_pageout_scan 可能会kill系统中最大的进程。Linux也使用不同的页面链表。物理内存被分为(多个)3重zone:一个DMA页面,一个普通页面,一个动态分配内存页面。zone的实现很像由于x86架构限制而很产生的。页面在hot,cold和free链表间移动--机制和FreeBSD的类似。经常用的页面在 hot上。可用页面则在cold或者free上。
SUN的大佬使用free链,哈希链,vnode页面链支持自己的LRU实现。后两者大致相当于FreeBSD和Linux的active/hot链--也是FreeBSD和Linux要扫描的链。Solaris要扫描的不是这两个对象,它用two-handed clock算法扫描全部页面(见Solaris Internals 或其他什么地方随你便)。大致方法是,两只手相隔固定举例,前面的手将page的引用位清空以作为标识,如果自此开始没有进程引用这个页,后面的手就释放这个页面(当然如果需要就写回磁盘)。
3个系统在分页时都考虑了NUMA本地性。他们都把IO buffer cache和虚拟内存页面的cache合并到一个系统页cache中。系统页cache用于读写文件已经被mmap了文件,还有应用的text段和data段。
文件系统
3个系统都使用数据抽象层向应用隐藏文件系统实现细节。就是用大家熟悉的open,close,read,write,stat,等等系统调用访问文件,无论下层的文件数据的实现和组织如何。Solaris和FreeBSD把这种机制称为VFS(virtual file system),基本数据结构是vnode(virtual node)。Solaris和FreeBSD里每个被访问的文件都有一个赋给他们的vnode。除了generic 的文件信息外,vnode还包含到file-system-specific 信息的指针。Linux采用了详细的机制,也叫VFS(virtual file switch),文件系统无关的数据结构是inode。这个机构和vnode类似(小心:Solaris和FreeBSD也另有自己的inode--是 UFS文件系统里file-system-dependent 的数据)。Linux还有两个不同的结构,一个用于文件操作,另一个用于inode操作。Solaris和FreeBSD将他们合并为vnode操作。
VFS允许在系统里实现多种文件系统。这意味着他们相互访问对方的文件系统没问题。只要相关的文件系统例程和数据结构已经被移植到VFS上。所有这3个系统都允许文件系统堆叠stacking。下表列出了每个OS实现的文件系统类型,不是全部哈。
图片附件: fs.png (2006-7-1 23:22, 28.97 K)
screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='点击在新窗口查看全图/nCTRL+鼠标滚轮放大或缩小';}" onmousewheel="return imgzoom(this);">
结论
Solaris,FreeBSD和Linux显然都在从对方身上获益。随着Solaris的开源,这种相互促进有望更快。Max个人已经感觉到 Linux的变化是最快的。新技术被快速地集成进系统,只是文档和健壮性可能有点落后。Linux有很多--或者有时是看上去有很多--开发者。 FreeBSD则大概是(从某种意义上)3个系统中历史最长的。Solaris来自BSD Unix和AT&T Bell实验室Unix的结合,使用了更多数据抽象层,因而一般说来能更简便地支持更多功能。不过,内核中大多数这样的分层都没有文档描述。可能随着代码的开放这一点会有所改善。
至于他们的差别,最大的地方之一是page fault处理了。在Solaris中,发生page fault时,代码是从平台相关的trap handler开始执行的(以大家的智商,这好像不用说了吧。。。),然后会调用generic的as_fault例程,这个例程判断发生page fault的segment,然后调用segment driver处理page fault。segment driver调用文件系统代码,后者再调用进驱动程序,换入页面。换入完成后,segment driver 调用HAT层来更新页表项。在Linux上,发生page fault后,内核调用的代码在会马上进入平台相关部分,这些处理可能更快,不过可能不太容易扩展和移植(后半段说得太省,不知道作者有没有真的研究过 Linux下对应的处理过程)。
内核观察和调试工具对正确理解系统行为有关键意义。在这方面,Solaris有kmdb,mdb和DTrace 。在开源之前,Max就对Solaris做过多年“反向工程”--他发现解决问题的时候使用工具总比阅读代码来得快--我也知道,不过得看什么场合,大家可不要被他误导。Linux嘛,我看作者Max不太熟,所以认为没有太多工具。对FreeBSD,他也认为只是可以用GDB调试内核的dump-- Liux也可以。
(e129)
[ 本帖最后由 compnik 于 2006-7-1 23:24 编辑 ]
实现s3c2510拨号全过程小结
摘要:
实现视频服务器的pppoe拨号功能
平台:
03版的uclinux
s3c2510的芯片
编译器原来是03版的,后来我改为04版的arm-elf.....2004.sh
一 配置内核
配置内核,使系统内核支持ppp协议,这是最基本的工作。
make menuconfig
选择network device support
然后选择下面所有的ppp协议
退出
二 安装pppd,pppoe
我的弯路主要就是在这里
我一开始不知道uclinux的user里本身自带了pppd,rp-pppoe的安装程序,于是到网上down了安装程序进行
移植,虽然后来经过升级编译完成了移植,但是最好还是用uclinux自带的程序,这样可以避免很多兼容性的
问题(uclinux自带了很多非常有用的组件,大部分常用的功能都能从user目录下找到)。安装过程
make menuconfig
customize vendor/user settings
选择
network applications
pppd
rp-pppoe(别忘了pppd下面还有这个要选择)
Miscellanenous Applicaions
chat (这个进程在连接上后有用)
好了,配置好内核后,不要急于make,还有个地方要改
cd user/pppd/ppd/
修改lcp.c
把 1459行改为:Orc=CONFNAK
好了,接下来回到系统目录make dep ->make
如果在编译过程中出现错误应该根据错误提示进行修改,在这里不排出因为编译器版本过低无法编译pppd的原因,
最好使用04版的arm-elf-gcc。
编译成功后,应该可以在romfs/bin下找到pppd,pppoe,chat这三个我们要生成的东西了。
网上有资料说还要生成pppstatus,pppdump这两个东西,但我觉得这两个文件不是必要的,如果真的需要就到/user/ppd/ppd里
手动生成这两个文件然后,拷贝到romfs/bin目录下。
现在,通过上面的步骤,我们已经在romfs/bin生成了
生成了pppd,pppoe,chat,pppstatus,pppdump这五个文件了,除此之外我们还需要一些配置文件,主要用来保存拨号的用户名
和密码。在romfs目录下建一个ppp目录用来存放配置文件,然后把user/pppd/etc.ppp下的chap-secrets,pap-secrets,options
文件拷贝到我们刚才建的那个目录。在chap-secrets,pap-secrets文件里写下我们要用来拨号的用户名和密码,格式如下
“test” * “password”
好了,现在我们来确认一下pppd能不能正常启动
我们把生成的image文件download到目标板上
运行/bin/pppd,如果能够打印出乱码的话,说明pppd已经移植成功了。
非常不幸,我在 运行/bin/pppd后没能打出乱码,根本无法启动pppd
是什么原因导致pppd退出呢,系统也没有提示,郁闷!在这里搞了很久,为了弄明白系统在执行pppd的时候到底是什么原因
退出,我决定在busybox里安装一个syslogd用来显示日志内容。
安装方法很简单,就在vender /user settings里选busybox然后选择syslogd,重新编译。
好了,现在我的s3c2510有日志可查了,我再次运行/bin/pppd后,出现提示,找不到/dev/ppp
这时我才知道,原来uclinux是不默认建立ppp的设备节点的,要自己手动建立一个ppp节点。
手动建立一个ppp节点:
进入linux主机下的/dev
file ppp
得知ppp是字符设备,主设备号是108,次设备号是0
使用下面这个命令生成
touch /dev/ppp @ppp,c,108,0
把@ppp,c,108,0烤到romfs/dev下面,重新编译生成image。
完成了节点的建立后,再在目标板上运行 /bin/pppd,令人兴奋得乱码终于出现了,和主机上的情况一样,在这里我们就
姑且认为pppd已经移植成功了。
三 测试环境的建立
在我们真刀真枪地使用modern来拨通ISP之前,我们可以先自己用windowXP建立一个PPPOE服务器,然后使用直连线
把我们的目标板和XP服务器连接起来,在目标板上对XP进行拨号测试。拨号成功后,我们在使用modern拨ISP。当然拨
XP服务器和拨ISP的方法基本上是一样的。
建立XP服务器
1 下载RASPPPOE_098B组件
2 右击网上邻居,选属性,点安装,选择协议,添加,从磁盘安装,然后选择RASPPPOE_098B的目录
安装好组件后,你便可以在本地连接中看到ppp oever ethernet prototal
3, 建立一个基于ppp的传入连接(我们的目标板拨号连接XP的pppoe服务器,靠的就是这个连接)
1)新建网络连接->选择设置高级连接->接受传入的连接->选择REALTEK ....(这是我的网卡)->允许虚拟连接
2)在这里你可以选择或新建一个用户用来被客户端拨号使用
3)一路next
四 开始进行拨号
1)利用我们在第三步建立的平台来进行拨号测试
确定目标板已经可以和XP服务器进行通信,(用直连线相连或连在同一局域网)
在目标板上运行测试命令
/bin/pppd pty '/bin/pppoe' user frankie &(这里请用你的chap-secrets的用户,当然这个用户必须是在XP服务器上
有登记的)
非常不幸,在我运行/bin/pppd pty '/bin/pppoe' user frankie &后,出现了LCP:timeout config-request sending
等一堆错误。
在这里卡住之后,查了很多资料,好像比较麻烦。无奈之下,我决定改用05版uclinux的rp-pppoe。
哈哈,想不到05版的东西那么好用,重新编译后,再允许测试命令。
终于拨号成功了
ifconfig后也终于出现了ppp0.
2)由于硬件环境限制,暂时不对moden进行直接拨号测试。
五 参考资料
参考资料全部来自INTERNET
六 后记
出于用户友好性的考虑,我想可以做成用网页的形式来给客户进行拨号,这样是否更有意思呢
[ 本帖最后由 upcuiling 于 2006-7-3 10:56 编辑 ]
请问专家们:Redhat AS4下怎么建裸设备? 谢谢!(跟AS3不一样)
内核模块创建在proc文件系统上建立_ps文件.遍例进程内核链表task_struct.将遍例结果存入缓冲区.影射到/proc/_ps文件中.用户态的程序去读取 这个文件.打印显示 当前进程的的pid,ppid 和进程名.
CODE:[Copy to clipboard]#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
MODULE_AUTHOR("mq110");
static int ps_read(char *page, char **start, off_t offset,int count, int *eof, void *data)
{
static char buf[1024*8]={0};
char tmp[128];
struct task_struct *p;
if(offset >0)
return 0;
memset(buf,0,sizeof(buf));
read_lock(&tasklist_lock);
for_each_process(p) //遍例内核进程链表.
{
sprintf(tmp,"%d/t/t%d/t/t/t%s/n",p->pid,p->parent->pid,p->comm);
strcat(buf,tmp);
memset(tmp,0,sizeof(tmp));
}
read_unlock(&tasklist_lock);
*start=buf;
return strlen(buf);
}
static __init int ps_init(void)
{
struct proc_dir_entry *entry;
entry = create_proc_entry("_ps", 0444, &proc_root); //建立/proc/_ps文件.
if(entry == 0)
{
printk(KERN_ERR "create_proc_entry failed!/n");
return -1;
}
entry->mode = S_IFREG | 0444;
entry->size = 0;
entry->read_proc = ps_read;
return 0;
}
static __exit void ps_cleanup(void)
{
remove_proc_entry("_ps", &proc_root);
}
module_init(ps_init);
module_exit(ps_cleanup);以下是Makefile. TARGET改名成程序名就OK了.
CODE:[Copy to clipboard]TARGET = 006
obj-m := $(TARGET).o
KERNELDIR=/lib/modules/`uname -r`/build
PWD=`pwd`
default :
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
install :
insmod $(TARGET).ko
uninstall :
rmmod $(TARGET).ko
clean :
rm -rf *.o *.mod.c *.ko以下是用户态程序:
CODE:[Copy to clipboard]#include
#include
int main()
{
FILE *fp;
char buf[1024];
fp=fopen("/proc/_ps","r");
if(fp==NULL)
{
perror("fopen");
return -1;
}
printf("pid/t/tppid/t/t/tcommand/n");
while(!feof(fp))
{
if(fgets(buf,sizeof(buf),fp)!=NULL)
printf("%s",buf);
}
fclose(fp);
return 0;
}make ;make install 之后 编译用户态程序.
执行结果:
[root@Firewall 006]# ./likeps
pid ppid command
1 0 init
2 1 migration/0
3 1 ksoftirqd/0
4 1 watchdog/0
5 1 migration/1
6 1 ksoftirqd/1
7 1 watchdog/1
8 1 migration/2
9 1 ksoftirqd/2
10 1 watchdog/2
11 1 migration/3
12 1 ksoftirqd/3
13 1 watchdog/3
14 1 events/0
15 1 events/1
16 1 events/2
17 1 events/3
18 1 khelper
19 1 kthread
24 19 kacpid
100 19 kblockd/0
101 19 kblockd/1
102 19 kblockd/2
103 19 kblockd/3
106 19 khubd
197 19 pdflush
198 19 pdflush
199 1 kswapd0
200 19 aio/0
201 19 aio/1
202 19 aio/2
203 19 aio/3
288 19 kseriod
392 1 kjournald
1224 1 udevd
1941 1 kjournald
1944 1 kjournald
1967 1 kjournald
2820 1 syslogd
2824 1 klogd
2840 1 sshd
2852 1 vsftpd
2862 1 gpm
2882 1 atd
3184 1 mingetty
3185 1 mingetty
3186 1 mingetty
3187 1 mingetty
3188 1 mingetty
3189 1 mingetty
6819 1 mysqld_safe
6846 6819 mysqld
7475 1 smbd
7476 7475 smbd
7480 1 nmbd
19400 2840 sshd
19404 19400 bash
[ 本帖最后由 mq110 于 2005-12-29 14:05 编辑 ]