基于嵌入式Linux智能遥控器系统研究与设计
3.3嵌入式L i nux系统的移植
3.3.1嵌入式Li nux系统
Lm_ux系统与UNIX系统兼容,开放源代码,广泛应用于嵌入式设备。针对嵌入式
设备,许多Linux改良品种迎合了嵌入式/实时市场。它们包括RTLinux(实时Linux)、
uClinux(用于非MMU设备的Linux)、Montavista Linux(用于ARM、MIPS、PPC的
Linux分发版)、ARM—Linux(ARM上的Linux)和其它Linux系统。与其他嵌入式操作
系统相比,嵌入式Linux应用于智能遥控器系统至少具有以下优点:源码开放,软件资
源丰富。开放源码使开发获得了最大的自由度。软件资源丰富,每一种通用程序在Internet
上都可以找到;内核功能强大,性能高效、稳定,多任务;支持多种体系结构。可以移
植到数十种硬件平台上,特别是对当前流行的ARM处理器有很好的支持;完善的网络
通讯、图形、文件管理机制,大小、功能都可定制;良好的开发环境。有着非常优秀的
完整开发工具链,有十几种集成开发环境,其中很多是免费的。
3.3.2开发环境的建立
与其它操作系统相比,Linux最大的特点:它是一款遵循GPL的操作系统,可以自由
地使用、修改、和扩展【221。正是由于这一特色,本文采用这一操作系统。为了让Linux
在本系统的基于$3C2410A的硬件平台上正常运行,必须对其进行移植。
交叉编译[23,24】是指在一个平台上生成另一个平台上的可执行代码。而交叉编译器就
是在本地机器上可以运行的编译器,用它编译生成的可执行文件在本地机器上不能运
行,是为另一个平台准备的。
目前一般采用的解决办法是首先在主机端(可称之为HOST)编写程序,通过交叉编
译生成目标平台上(可称之为Target)可运行的二进制代码,再下载到目标平台上的特定
位置运行。在主机端和目标板之间需要通过某种方式进行通信,如使用RS232串口、以
太网等。目的在于发送控制指令和传输数据,同时获得反馈信息。如图3.13所示。
RS232/
Ethertna/
J1’AG
目标机(Target)
图3.13交叉编译环境建立主机和目标机的通信示意图
一个完整的交叉编译器跚包括以下几个部分:交叉编译器(GCC),库文件(Glibc),
调试工具(GDB),Linux头文件,以及一些常用的操作二进制文件的工具((Binutils)。由
于Linux内核对编译器有很大的依赖性,所以不同版本的Linux需要相应版本的编译器
一一一一
江苏大学硕士学位论文
编译。本系统使用cross.2.95.3版本的编译器。
首先启动PC机的Linux系统,然后拷贝cross-2.95.3.tar.bz2文件至1]/usr/local。接着,
安装交叉编译器。在终端窗口输入以下命令:
撑mkdir-p/usr/local/arm
j|≠tar xjvf cross-2.95.3.tar/bz2
群mv 2.95.3/mr/local/arm
撑export PATH=$PATH:/usr/local/axm/2.95.3/bin
这样,编译器就安装完毕了。如果输入命令arm.1inux.gCc-.version后能有版本显示
则交叉编译环境已经建立好了,如果没有版本号出现,注意让PC机的Linux重启或者
登出再重新登录进系统。
3.3.3 BootIoader的移植
3.3.3.1 Bootloader简介
Bootloaderl26】就是在引导操作系统内核或用户应用程序之前运行的第一段程序代
码,其主要功能是完成处理器和周边电路正常运行所需要的初始化工作,建立内存空间
的映射(包括设置系统堆栈和系统启动参数区等),将系统的软、硬件环境带到一个合
适的状态,并可以从ROM,FLASH等非易失存储器上,甚至网络上加载操作系统,以便
最终引导操作系统或用户应用程序【271。图3.14是一个同时装有Bootloader、内核启动
参数、内核映像和根文件系统映像的典型固态存储设备的空间分配结构示意图。
启动参数
0_L~曼譬。},,..一警文吁l矗∥“£
图3.14 Bootloader所处的层次位置
嵌入式系统上的Bootloader的功能要求多样化,不仅包括从存储介质中读取操作系
统并加以执行,还必须担负其最初的硬件初始化和一些硬件的检测功能(即PC机上BIOS
所完成的部分功能)。Bootloader是依赖于硬件而实现的,所以在嵌入式开发中建立一
个通用的Bootloader几乎是不可能的,通常也都需要对已有的Bootloader进行移植工作,
如annboot、blob、redboot、vivi和UBoot等。本系统设计时完成了Ⅵvi代码在$3C2410A
平台的移植工作。
为了满足Bootloader的专有性和灵活性需要,大多数Bootloader的代码都由
stagel和stage2两部分组成【2引。其中,依赖于MPU体系结构的代码,如MPU及存储管
理部件初始化代码等,通常都放在stagel中,并用汇编语言来实现,以达到短小精悍
的目的。stage2则通常用C语言等高级语言来实现,这样可以实现比较复杂的功能,并
且使程序具有更好的可读性和可移植性。Bootloader的执行流程如图3.15所示。
19
江苏大学硕士学位论文
图3.15 Bootloader执行流程图
3.3.3.2 Bootloader的移植
由于读写NAND FLASH要对其控制器编程,一般不能直接将其作为启动代码存储设
备。但是本系统中采用的$3C2410A提供了这样一种机制,它在启动的时候能自动将NAND
FLASH中前4k的内容拷贝到内部的4k SRAM中,并将SRAM的基地址映射为Ox00000000,
因此在设计Bootloader时,如果在前4k的代码中,能够通过对NAND控制器进行编程,
将其后的代码拷贝并重新定位到内存中,就完全可以不使用NOR FLASH,既节省了电路
板的空间,又降低了成本,更重要的是,可以大大缩短系统的启动时间。具体的设计过
程如下: 一
在stagel阶段中:
1)设置异常向量表
2)初始化处理器
3)基本的硬件初始化
4)为加载stage2作准备
为了获得更快的执行速度,通常把stage2加载到RAM空间中来执行,因此必须为加
载BootLoader的stage2准备好一段可用的RAM空间范围。部分程序代码如下:
mov rl,#0x53000000
mov r2,#OxO
strd,[r1]
mov rl,#INT—CTL—BASE
mov r2,#Ozffffffff
str r2,#[r1,#oINTMSK]
Idr r2,=OxTff
str r2,[rl,#oINTSUBMSK]
mov rl,#CLK_CTL_BASE
mvn r2,##Off000000
str r2,[r l,#oLOCKTIME]
mov rl,#CLK—CTL—BASE
mov r2,#Ox3
str r2,[rl,#oCLKDIVN]
mrc p15,0,rl,cl,cO,0
orr rl,r1。#Oxc0000000
TI上I虽
TlI州l上 一一一一一
江苏大学硕士学位论文
mcr p15,0,rl,cl,cO,0
mov rl,#CLK CTL_BASE
Idr‘
r2,mpll一203mhz
str r2,[rl,#oMPLLCON]
bl memsetup
#i fdef CONFIG__S3C241 0—NAND—B00T
bl copy_myself
ldr rl,=on—the_ram
add pc,rl,并O
nop
nop
1:b lb
on the ram:
#endif
l dr sp,DW_STACK_START
mov fp,#O
mov a2,#0
bl main
mov pc,#FLASH—BASE
Idr rO,=VlVl—RAM_BASE
mov rl,#OxO
mov r2,#Ox20000
bl nand_read_ll
由于stage2通常是C语言执行代码,因此在考虑空间大小时,除了stage2可执行映
象的大小外,还必须把堆栈空间也考虑进来。此外,空间大小最好是memory page大小
(4KB)的倍数,1M的RAM空间己经足够了。将stage2的可执行映像安排到从系统RAM起始
地址开始的lM空间内执行。具体的地址范围可以任意安排,因此,可以将stage2安排到
整个RAM空间的最顶1MB。
为了后面的叙述方便,这里把所安排的RAM空间范围的大小记为:stage2一size(字
节),把起始地址和终止地址分别记为:stage2_start和stage2一end(这两个地址均以4
字节边界对齐)。因此:
stage2_end 2
stage2一start+stage2一size
另外,还必须确保所安排的地址范围是可读写的RAM空间,因此,必须对所安排的
地址范围进行测试。具体的测试方法采用:以memory page为被测试单位,测试每个memory
page开始的两个字是否是可读写的。为了后面叙述的方便,记这个检测算法为:
test_mempage,其具体步骤如下:
1)先保存memory page一开始两个字的内容。
2)向这两个字中写入任意的数字。
3)将这两个字的内容读回。显然,我们读到的内容应该分别是0x55和Oxaa。如果
不是,则说明这个memory page所占据的地址范围不是一段有效的RAM空间。
4)恢复这两个字的原始内容。测试完毕。
为了得到一段干净的RAM空间范围,也可以将所安排的RAM空间范围进行清零操作。
拷贝自己到内存。拷贝时要确定两点:第一,stage2的可执行映象在固态存储设备的存
放起始地址和终止地址;第二,RAM空间的起始地址。
21
江苏大学硕士学位论文
5)跳转到内存。
6)建立堆栈指针。
堆栈指针的设置是为了执行C语言代码作好准备。通常可以把sp的值设置为
(stage2一end一4),也即如前所述安排的那个IMB的RAM空间的最项端(堆栈向下生长)。
●跳转到stage2的C函数入口处。
在上述一切都就绪后,就可以跳转到Boot Loader的stage2去执行了。
在stage2阶段中:
1)初始化本阶段要使用到的硬件设备
这包括:初始化一个串口,以便和终端用户进行I/0输出信息:初始化计时器,初始
化网络设备等。在初始化这些设备之前,也可以重新把LED灯点亮,以表明己经进入main0
函数执行。设备初始化完成后,可以输出一些打印信息,程序名字字符串、版本号等。
2)检测系统的内存映射((memory map)
所谓内存映射就是指在整个4GB物理地址空间中有哪些地址范围被分配用来寻址
系统的RAM单元。
3)进入命令循环
接收用户从串口输入的命令,然后做相应的工作。当系统进入命令循环后,开始
接受用户命令。可以启动一个定时期,并设置一段时间,如果在这个时间内没有任何输
入则自动加载内核映像。
4)加载内核映像
●规划内存占用的布局
在规划内存占用的布局时,主要考虑基地址和映像的大小两个方面。
●从Flash上拷贝
由于像ARM这样的嵌入式MPU通常都是在统一的内存地址空间中寻址FLASH等固
态存储设备的,因此从FLASH上读取数据与从RAM单元中读取数据并没有什么不同。用一
个简单的循环就可以完成从Flash设备上拷贝映像的工作:
while(count){
木dest++=木src++:
Count-=4; }
●设置内核的启动参数
在将内核映像和根文件系统映像拷贝到RAM空间中后,就可以准备启动Linux内核
了。但是在调用内核之前,应该作一步准备工作,即:设置Linux内核的启动参数。Linux
2.4.x以后的内核都以标记列表(tagged list)的形式来传递启动参数。启动参数标记列
表以标记ATAG_CORE开始,以标记ATAG NONE结束。每个标记由标识被传递参数的
tag_header结构以及随后的参数值数据结构来组成。数据结构tag和tag header定义在
Linux内核源码的include/asm/setup.h头文件中。
在嵌入式Linux系统中,通常需要由Bootloader设置的常见启动参数有:ATAG_CORE,
ATAG MEM,ATAG , , 等。._MDLINEATAG RAMDISK ATAG INITRD
江苏大学硕士学位论文
采用如下代码设置ATAG_CORE:
params=(struct tag*)BOOT PARAMS:
params一>hdr.tag=ATAG_CORE:
params一>hdr.s ize=tag_s ize(tag_core):
params一>u.core.flags=O:
params一>u.core.pages i ze=O:
params一>u.core.rootdev=O:
params=tag_next(params):
其中,BOOT_PARAMS表示内核启动参数在内存中的起始基地址,指针params是一个
struct tag类型的指针。宏tag_next0将以指向当前标记的指针为参数,计算紧临当前
标记的下一个标记的起始地址。内核的根文件系统所在的设备ID就是在这里设置的。
采用如下代码设置内存映射:
for(i=O:i<NUM_MEM_AREAS:i++){
if(memory map[i].used){
params一>hdr.tag=ATAG MEM;
params一>hdr.size=tag_si ze(tag_mem32):
params一>u.mem.start=memory_map[i].start:
params一>u.mem.size=memory_map[i].size;
’params=tag_next(params):
)
}
在memory rap[]数组中,每一个有效的内存段都对应一个ATAG—EM参数标记。
Linux内核在启动时可以以命令行参数的形式来接收信息,利用这一点可以向内核
提供那些内核不能自己检测的硬件参数信息,或者重载(override)内核自己检测到的信
息。采用这样一个命令行参数字符串”console=ttySO,i15200n8”来通知内核以ttySO作
为控制台,且串口采用”115200bps、无奇偶校验,8位数据位”这样的设置。
5)调用内核
Bootloader调用Linux内核的方法是直接跳转到内核的第一条指令处,也即直接
跳转到MEM START十Ox8000地址处。
当控制权交给Linux内核后,Bbootloader的使命也就完成了。通过这样的
Bootloader设计方法,能够摆脱系统启动对NOR FLASH的依赖。Main函数的主要源码如
下:
int main(int argc,char*argv口)
{
int ret:
putstr(’\r\n”):
putstr(vivi banner):
江苏大学硕士学位论文
reset handle0:
ret=boardee—init 0:
if(ret){
putstr(”Failed a board initQ procedure\r\n’):
error():
)
mem_map_init():
眦叭一init():
putstr(”Succeed memory mapping.\r}n’):
ret=heap_ini t 0:
if(ret){
putstr(”Failed initailizing heap region\r\n’):
error 0:
}
ret,mtd_dev_init 0:
init_priv_data():
misc():
init_builtin_cmds 0:
boot—or—vivi():
return 0:
}
3.3.3.3 Bootloader的烧写
烧写Flash的工具很多,比如F1ashPG卅wiggler,Fluted,sjfZ410等。本系统中采
用sjt2410工具通过JTAG对NAND Flash进行烧写。首先,将目标系统上的JTAG接DJ9与
PC的并口相连接,为烧写BootLoader做好了硬件上的准备。其次,确认并口驱动已安装。
在Windows命令行模式下,执行sjf2410.exe文件目录下的命令sjf2410.exe/f:vivi,即
可将Bootloader烧写到系统中。
3.3.4 Li nux内核的移植
所谓移植,就是使一个实时嵌入式操作系统内核在某个微处理器或微控制器上运
行。由于嵌入式操作系统是“可裁剪’’的,依赖于硬件电路的设计。因此,嵌入式操作
系统必须根据硬件电路对已有的内核代码进行修改移植,才能正确运行。
移植过程不需要编写大量的新代码,只需从相近的体系结构中选取所需的代码。其
中主要部分是内核入口部分、处理器和体系结构初始化部分、端口映射部分和中断初始
化部分。
根目录只需修改Makefile文件。这个文件的任务有两个:产生vmlinux文件和产生内
核模块。为了达到此目的,Makefile将递归进入内核的各个子目录中,分别调用位于这
江苏大学硕士学位论文
些子目录中的Makefile。内核编译是根据Makefile文件的指示进行的,可以在这个文件
中指定使用的编译器等信息。Makefile用来组织内核的各模块,记录了各模块间的相互
联系和依赖关系。我们无需移植每一个Makefi le文件,因为大部分工作都在内核最上层
目录下的Makefile中完成了。
打开最上层目录下的Makefile文件,该文件中需修改的内容如下:
1)指定目标平台.
移植前:ARcH:=$(shell uname-m sed-e/i.86/i386/⋯⋯)
移植后:ARCH:=arm
2)指定交叉编译器
移植前:CROSS_COMPILE=
移植后:CROSS_COMPILE=arm-l inux一
移植要点:设置目标平台和交叉编译器。
3.3.4.1红外通信协议的移植
红外传输协议栈【29】的结构如下图3.16。
信息访问
局域网访问对象交换协议模拟串口层
服务协议
协议(IrLAN) (Ir0BEx) 协议(h-COWW)
(IAS)
流传输协议(TinyTP)
连接管理协议(IrlJlIP)
连接建立协议(IrLAP)
物理层协议(IrPIll『)
图3.16红外协议栈
如果将以上的红外协议层集成在一个嵌入式系统中,大体可以分为三个模式:驱动模
式、中断模式和用户模式部分,如图3.17所示。其中处于最低层的是物理层,是由红外
收发器件和UART或者其他专用控制器组成。UART或者专用控制器将输入的数据流转
换成一定调制方式的电流脉冲,然后输出到红外收发器件,由收发器件将电流脉冲转换
成红外光脉冲。在物理层的上面是协议栈中的中断块负责响应外控制器的接收发送中
断。其中很重要的工作就是进行帧的处理,保证数据传输的正常进行。驱动部分是协议
栈的最主要的部分,包括了IrLAP,IrLMP,TinyTP和IAS等协议。这些协议实现了红
外协议的底层功能,IrLAP建立通信连接;IrLMP实现红外连接的管理和复用;TinyTP
对数据传输的进行流控制;等等。用户部分包括IrOBEX以及其他的应用协议和应用程
序,用户应用程序可以直接使用驱动部分的协议或者通过应用程序间接使用L30]。
江苏大学硕士学位论文
图3.17红外协议栈在嵌入式系统中的实现
整个红外协议栈比较庞大复杂,在嵌入式系统中,由于微处理器速度和存储器容量
等限制,不可能也没必要实现整个的红外协议栈。因此可以将协议栈简化,根据实际需
求,有选择地实现自己需要的协议和功能即可。
在linux下也提供了相关红外协议的支持,具体配置如图3.18所示:
二一翻I巾A O掰r删subsystem supp矾
l旧l^protocols
口}儿AN prcx嚣ol
翻I一:OMM p峨佚d
口Uh哺((on删KtIoI嘲!ss’pnxocd
Irl3姨O口llons
嗣CKk Ia致Ls【^P
口Fast RRS《Iaw latencyI 国淡b∞l翩amm
医lnI捆,ed.∞n device dm,e懵
图3.18红外协议栈移植配置
IrLAN protocol:该协议模仿以太网,可以利用红外光束组建一个无线网。在本应
用中不涉及,所以不需要选。IrCOMM protocol:这是实现仿真虚拟串口协议,通过该协
议,已存在的,通过红外连接可以识雯JlJTTY的应用,比如PPP和minicom用中需要使用虚
拟串口进行红外信号传输,故需要选上。
Ultra(connectionless)protocol:该协议允许你简单地通过红外设备交换数据,而
不需要经过红外协议(没有握手、没有操纵帧和简单固定的帧头)。该协议支持在固定的
套接字下有效:socket(AF IRDA,SOCK DGRAM,1)。在本应用中不需要使用红外套接字进
行通信,所以不需要选。
Cache last LASP:选中该项是使IrLMP缓存上一个己用的LASP。这一项很有意义,
因为许多帧的发送和接收都是使用相同的连接,而选中这一项可以为每一个帧保存一个
江苏大学硕士学位论文
哈希查找。
Fast RRs:这一项是当作为主站时,IrLAP发送快速接收准备好帧。不选中这一项则
会有很糟糕的延迟:选中这一项可以使红外栈发送更多的包。该项适用于有主站和从站
的场合,故在本应用中不需要。
Debug information:选中这一项是使红外子系统能将调试信息写入系统日志,同时
还会做额外的内部校验,这样可以在出现错误时,阻止内核崩溃。可以在/proc/sys/
net/irda/debug目录下改变调试等级。
3.3.4.2红外驱动的移植
在系统中,是使用红外线收发器来接收和发送红外信号的,不涉及红外USB适配器
的驱动支持,所以在涉及dongl和USB的选项都不需要选,本文系统的红外驱动具体配置
情况如图3.19所示(红外驱动开发在第五章中有具体的论述)[311..
SlR‘k蚋ce翻vels
口l胛Y(uses LJu sett,宙dstved
翻$3c2410 Ircla support
D仪Igle support
口Serial do啷lIe support
Old SlR device dIIver;
团l萨0盯ar队sedaJ ddver)
oⅪSePal幽翱如suppo疗
口Old SerW dc聃和suppoM
同R device翻veB
口I,口^USB dorIQies
口519maTd STIM杓O脚(EXPERIMENTAL)
图3.19红外驱动移植
IrTTY(uses Linux serial driver):支持IrTTY线路规章。
s3c2410 irda support:支持s3c2410开发板红外线收发器的驱动。
IrPORT(IrDA serial driver):红外设备串口驱动,它可以取代IrTTY并且在某些情
况下还会更好。比如红外端口没有echo—canceling时,使用IrPORT也会正常工作,因为
IrPORT只工作在半双工模式。你只需要象插入FIR驱动的方式插入IrPORT最P可(insmod
irport io=ox3e8 irq=11),而不需要使用irattch,但需要注意的是IrPORT只是一个红
外串口(Serial Infrared)设备驱动,它的速度最高不超过115200bps。
3.3.4.3红外工具集irda-utils移植
irda—utils是用于红外设备之间进行红外线交流的工具。Linux-IrDA计划是一个从
零开始编写的GPL对IrDA的实现,被支持的IrDA协议包括IrLAP,IrLMP,IrIAP,IrTTP,
IrLPT,IrLAN,IrCOMM和IrOBEX。irda-utils软件包包括一组能够使用IrDA协议的应用程
序,这些应用程序包括:
findchip:用于查看红外设备的芯片类型,使用方法为./find—v。
irattach:用于将linux IrDA栈与一个特定的红外设备绑定。因此,为了在Linux机
江苏大学硕士学位论文
上使用IrDA,必须要做这项工作。irattach需要在root权限运行。使用方法为./irattach
<dev>一s.其中dev通常是一个tty名,但也可以是一个红外设备名;-s是发现远程红外设
备。运行该应用程序后,在/proc/net/irda/discovery文件中会记录己发现的红外设备
信息。
irdadump:该应用程序用于显示通过红外连接接收和发送的所有帧信息。
irdaping:该应用程序用于使用测试帧ping一个远程设备。但并不是所有的设备都
实现了对测试帧的支持。
irsockets:使用红外套接字的程序。
多数IrDA功能在内核中己经实现,因此在使用任何IrDAT具或程序前必须让内核启
用IrDA支持。
红外工具集irda-utils的移植实际上就是安装irda-utils,其安装过程有些特殊,
因为从它的Makefile文件中可以看出,它是对其包里的应用程序逐个生成Makefile文件
的,以后的安装是按应用程序逐个进行的。其具体安装步骤如下:
命令[root@localhost irda—utils一0.9.17]#make生成各个应用程序的Makefile。
生成Makefile后,以后各个应用程序的安装完全相同,下面我以irattach的安装来说明。
进入irattach目录用[root@localhost irattach]#vi Makefi le命令修改其
Makefile中的部分内容。
修改内容如下:
CC=arm-l i nux—gcc(交叉编译器)
LD=arm-1 inux一1d(交叉链接器)
SYS_LIBPATH=一L/usr/l ib—L/root/usr/local/arm-l inux/l ib(库路径)
install:$(TARGETS)(设置将应用程序安装在什么地方)
instal l irattach$(ROOT)/root/rootfs—I/my root fs/usr/bin
install dongle—attach$(ROOT)/root/rootfs—I/my_rootfs/usr/bin
做出了以上的修改后,用以下的命令进行编译和安装。
[root@localhost irattach]#make
[root@localhost irattach]#make install
经过上面的过程后,irattach应用程序就成功地安装到了根文件系统的/usr/bin目
录下。但如果现在在S3C2410A硬件平台上执行./irattach命令会报错,因为它需要的库
还没有放到根文件系统中,无法找到。还需要通过以下步骤:
1)通过arm-linux—readelf-a“文件名’’l grep“Share"命令查看其需要的链接
库。
2)将链接库文件[1ibc.SO.6)拷贝到根文件系统的/lib目录下。
3)修改根文件系统的/etc目录下的profi le文件。
[root@localhost etc]#vi profile
export LD_LIBRARY_PATH=/I ib。
经过以上过程,./irattach命令就可以在$3C2410A硬件平台上成功执行了。其它的
江苏大学硕士学位论文
应用程序的安装可以安装相同的步骤进行即可。
3.4嵌入式Li nux根文件系统的实现
Linux支持许多文件系统类型,目前已达几十种。主要的有:EXT2/EXT3、ROMFS、
CRAMFS、YAFFS、JFFS/JFFS2等【32’331。其中后三种主要用于嵌入式系统。论文采用的
JFFS/JFFS2(Journal Flash Filing System)是基于日志的文件系统,目前可以支持
ROM、NOR FLASH、NAND FLASH芯片。JFFS2是JFFS的第二版。JFFS/JFFS2非常适合Flash
芯片上使用,即使在系统崩溃、非正常掉电的情况下,系统重新启动时也无需执行文件
: 系统的检查恢复。
3.4.1嵌入式Linux文件系统实现
具体过程如下:
1)在/dev目录中创建需要用到的Linux系统中使用的外部设备。
2.)在/etc目录中创建系统配置文件。
3)在/lib目录中建立所需的函数库。
4)在/bin和/sbin目录中,利用BusybOX建立基本命令工具程序和系统管理程序。
ausybOX,嵌入式Linux系统中的“瑞士军刀”,因为它将许多常用的UNIX命令和
工具结合到了一个单独的可执行程序中。虽然与相应的GNU工具比较起来,BusybOX
所提供的功能和参数略少,但在嵌入式系统中,已经足够了。
Busybox是一个多调用的二进制文件,它提供了POSIX式韵Linux命令最小子集,
大小也不过100K左右,适合于非常小的嵌入式系统。它包括ash shell.ifconfig halt,rebooL
mkdir,mount,In,ls,echo,cat等一些系统上常用的工具程序,而且使用ausybOX也很简
单。
3.4.2构建JFFS2根文件系统
3.4.2.1建立根文件系统源目录
首先在宿主机建立rootfs目录,作为“/’’目录,再在其中建立各个子目录:/dev、
/ete,/lib,/bin,/sbin,/usr,/proe,/tmp,/var,/opt。。
3.4.2.2添加文件
1)向/dev添加设备文件:
/dev目录中的设备文件及链接可以从Linux宿主机中拷贝。也可以使用mknod指令添
加。所有的Linux设备分为两大类:字符设备(用C表示)和块设备(用b表示)。每个设
备文件有一个主设备号和一个次设备号唯一表示,主、次设备号在Linux内核源码树的
Documentation/devices.txt文件中描述。
2)向/lib添加库文件:
在前文中,已将交叉工具链安装在/usr/local/arm/2.95.3目录中。将其中的一些库
文件及符号链接直接拷贝至Unib中即可,具体拷贝哪些库文件根据应用的需要而定。
如果Linux内核编译时有模块选项,就会产生对应的模块文件。这些模块文件就存
放在/lib/modules目录中,把它们拷贝过来就可以。。
江苏大学硕士学位论文
3)使用husybox构建几in与/sbin
busySox是一个源代码开放的软件工程,它集成了一百多个最常用的linux命令和工
具,还集成了一个http服务器和一个telnet服务器,所有这一切功能仅占用了1M Byte左
右的存储空间,非常适合嵌入式应用。常用的那些linux命令就如同分立式的电子元件,
而busybox就象是一个集成电路,把常用的工具和命令集成压缩在一个可执行文件里,
功能基本不变,而大小却小了很多倍。
能够做到这一点,得益于busybox巧妙的设计思想。标准的Linux的bin命令和程
序中,含有大量相同或近似的代码成分,它们同时存在于多个独立的命令程序中,因而
形成了代码冗余。Busybox在同一个可执行程序中实现若干个命令程序,因而能够实现
代码共享,消除了这种冗余,大大减小了最终命令文件的尺寸。
同时由于它也大大简化了嵌入式Linux系统中根文件系统的制作过程,因此在嵌入
式linux开发中,busybOX得到了非常广泛的应用。
使用busybOX编译生成Linux命令和工具程序的过程如下:
首先,从busybox的官方网站http://www.busybOX.net/download下载源代码(以
busybOX.1.2.1为例),然后解压缩到目录/busybox.1.2.1。在该目录中执行make help将列
出所有配置、编译busybOX的命令、目标选项及其说明。
进入该目录,执行make defconfig,将建立默认配置文件.config,它使能了除调试
选项之外的几乎所有的busybOX的选项。
然后,再执行make menuconfig,可以进入菜单式配置界面继续对busybox配置。
这个菜单式配置界面与Linux内核的配置界面非常类似。在这个配置界面,可以去除不
需要的基本命令选项,进一步减小代码尺寸。还可以配置必要的交叉编译与安装有关的
选项。
在Busybox Settings->Build Options菜单中,选中下面的选项:
【·】Build BusyBox as a static binary(no shared libs)
把busybox编译成静态链接的可执行文件,运行时独立于其他函数库。选中:
HDo you want to build BusyBox witll a Cross Compiler
选中,指定交叉编译器的位置/usr/10cal/arm/2.95.3
在Busybox Settings->Installation Options菜单中:【}】Don't use/usr
这个选项一定要选上,否则执行make install后busybox将安装在原系统的/usr下,
这将覆盖掉系统原有的命令。选择这个选项后,执行make install后会在busybox目录下
生成一个install目录,里面有busybOX和指向它的链接。
经过上述配置后,保存并退出配置界面。执行make命令,完成后再执行make install
命令,就会在busybOX.1.2.1目录建立install目录,其中就是最终的结果:
drwxr-xr-x 2 root root 4096 01.04 15:36 bin
lrwxrwxrwx l root root 11 01—04 15:36 linuxrc->bin/busybox
dFwxr-xr-x 2 root root 4096 01.04 15:36 sbin
两个目录bin和Sbin以及一个名为linuxl'c指向bin/busybox的链接文件。其中唯一
江苏大学硕士学位论文
的可执行文件busybox在bin目录下,其他的所有文件都是指向它的符号链接。虽然
一install/bin和_instalVsbin目录下的链接文件都是指向_instalVbin/busybOX这同一个可执
行文件,但由于链接名不同,它们执行时所完成的功能也不同。
使用busybOX时,直接输入链接名和对应命令的参数,它们将作为一个参数传递给
busybox,完成对应的功能。例如:Is-1
上列命令中,ls是链接名,.1是命令Is的参数,它们一起作为参数传给busybOX,
完成“Is-1”的功能。由此可见,对使用者来说,busybOX的使用方法与标准命令的使
用方法是完全一致的。
将busybOX.1.2.1/ 目录中所有的文件与拷贝到根系统的源目录.instal rootfs
中(覆盖rootfs中空的bin与sbin目录)。就实现了根文件系统bin与sbiIl目录中的常用
命令。
4)向/etc中添加配置文件
/ete目录存放系统的全局配置文件,它们与系统的启动过程密切相关。因此有必要
首先对LintLX系统的启动过程进行分析。
嵌入式Linux系统的启动过程可分为两个阶段。第一阶段主要是bootloadcr的运行
并加载内核,然后内核完成核心数据结构和硬件的初始化,加载各类驱动程序。第二阶
段就是所谓的“init"进程。它是内核启动的一个用户级进程,是系统上所有其它进程
的父进程、发起者、控制者。它能够观察它的子进程,在需要的时候启动、停止、重新
启动它们。“init’’进程会搜索根文件系统中的“init”程序,并运行它。“init”程序通常
位于/sbin或/bin目录下,负责在系统启动时运行一系列程序和脚本文件,与/etc目录中
的配置文件紧密配合,完成系统的各项配置。
在/ete目录中有一个重要的文件inittab,“init’’进程从这个文件获取所要运行的程序和
脚本、运行的时机等信息。在inittab文件中,每行语句都包含四个域,形如下面的格式:
id:runlevds:action:process
其中,id是指入口标示符,是一个字符串,由两个独特的字元所组成。这是id在
System Vsystem init中的含义:概括而言,Linux/Unix系统一般有两种不同的初始化启
动方式,一种是BSD system init方式,另一种就是System Vsystem init方式,以后一种
较为常用。前面介绍的busybox也有自己的启动方式,它与System Vsystem init方式较
相似。但在busybox的启动方式中,id是指所启动的控制台。
Runlcvd,叫运行级,是操作系统当前所处的功能级别,从0到6共7个级别,分
别具有不同的功能:
伊——停机
1——单用户模式
2——多用户模式,但没有NFS
3——完全多用户模式4_未使用
5——-X.windows模式
3l
江苏大学硕士学位论文
6-----系统重新启动
runlevels域指定后两个域action和process会在哪些runlevel中被执行。
action域指定init程序在执行相应的process时,对process所采取的动作,例如等
待、重新启动、只执行一次等。
process域是要执行的程序或命令等。
在前面介绍的busybOX的主要作用是实现Linux的常用命令,同时也提供了如何基
于busybOX制作根文件系统的文档和例子。其中如何基于busybOX制作根文件系统的说
明中提供了适用于busybOX启动的/etc目录中的配置文件。它们在examples/
bootfloppy/etc目录中:
撑pwd
/usr/tmp/busybOX-1.2.1/examples/bootfloppy/etc
.
群ls—1
.rw-1.¨r-.1 1 000 1 000 34 2006.07.O 1 fstab
drwxr-xr-x 2 1 000 1 000 4096 2006.07.O 1 init.d
.聊-1卜.r一.1 1 000 1 000 1 01 2006.07.01 inittab
-nⅣ一r.—r.-l 1 000 1 000 1 34 2006·07一01 profile
撑cdinit.d/
撑Is.1
-rwxr-xr-x 1 1 000 1 000 26 2006.07.0 1 rcS
在这个etc目录中有一个子目录init.d和三个文件,子目录init.d中又有一个rcS文
件。inittab文件为init进程提供信息,其内容如下:
::sysinit:/ete/init.d/rcS
::respawn:-/bin/sh
tty2::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount.a-r
它指定了系统初始化时执行的第一个脚本为/etc/init.d/rcS;当/bin/sh进程结束时就
重新启动;如果按下Ctrl+Alt+Delete就卸载所有挂接的文件系统。
reS中只有一条指令:mount_a。它用来挂接所有在fstab文件中指定的文件系统。
rcS脚本执行完后,将执行/bin/sh,进入Linux控制台窗口。这个过程没有登陆环节。最
后将执行/ete/profile脚本,执行用户指定的操作。
由这些分析可见,/etc提供了精简而必要的启动配置脚本,适用于busybOX启动。
因此,将这个etc目录中的内容全部拷贝到要制作的根文件系统的etc目录中,然后做
适当修改即可使用。
由于busybOX中的shell不是“Sh”,而是“ash’’,故所要作的修改有:
inittab文件改为:
::sysinit:/etc/init.d/rcS
::respawn:-/bin/ash
江苏大学硕士学位论文
tty2::askfirst:-/bin/ash
::ctdaltdel:/bin/umount.a—f
rcS文件第一行改为:
撑!,bin/ash
5)至此,所有必须添加文件的目录都已添加完毕,其余目录可暂时空着,在以后
需要时再添加。.
3.4.2.3制作根文件系统映像
本课题使用jffs2类型的根文件系统,所以使用工具软件mkfsjffs2来打包制作映像
文件。mkt'sjffs2的用法如下:
mkfs.jffs2—f../rootfs—e 2621 44-p-O./rootfs.jffs2
3.5本章小结
本章首先完成了智能遥控器系统的硬件平台的搭建,硬件平台的各个具体部分原理
图和总体PCB图在Protel 99 SE中设计完成。其次介绍了嵌入式Linux的发展与应用于
本论文设计的优势,具体给出了交叉开发环境的建立方法,然后分析了Bootloader的启
动过程,完成了Bootloader的设计与移植。最后详细分析了内核基于红外功能的移植、
文件系统设计和移植等嵌入式系统开发所涉及的重要环节。