Linux在嵌入式系统中的实现

发 布 时 间 : 2008-11-18 来 源 : 来自网络 作 者 : 匿名 浏 览 :

【摘要】 本文在对Linux的内核结构、启动过程进行分析的基础上,分析并给出了Linux内核向嵌入式系统中移植的方法,其中包括开发平台的建立、内核裁减的方法、内核在CF存储卡上的安装及引导过程。
【关键词】 Linux 嵌入式系统 内核 配置

1引言

当今,嵌入式系统在制造业、过程控制、通讯、航天、军事、家电等都有极为广泛的应用。随着微处理器的产生与发展,价格低廉,结构小巧的CPU和外设连接提供了稳定可靠的硬件架构,限制嵌入式系统发展的瓶颈就突出表现在了软件方面。嵌入式操作系统是嵌入式系统的灵魂。从八十年代末开始,陆续出现了一些嵌入式操作系统,比较著名的有Vxwork、PalmOs和Windows CE。而这些大多价格昂贵,并且源代码的封闭性也限制了开发者的积极性。由于Linux操作系统开放源代码,可以定制,价格低廉,功能强大,可以运行在X86、Alpha、Sparc、MIPS、PPC、NEC、ARM、 MOTOROLA等硬件平台上,众多商家纷纷转向了嵌入式Linux的开发。

2.Linux内核的分析

标准Linux在PC机上的最大安装大约需要至少2G的磁盘空间,由于嵌入式系统中资源有限,不能使用标准Linux的安装,而且嵌入式系统是针对特定应用的,不同的应用要求突出嵌入式操作系统某方面的功能,而对其他的功能则很少使用或者根本不需要,这就需要根据具体的应用对内核进行裁减,使其适应某专用系统。内核分析是内核裁减的基础,只有对内核的结构特性,以及引导过程有深入的了解,才能合理地裁减内核,使裁减后的内核在嵌入式系统中引导并运行。
2.1 Linux内核的抽象结构
一个完整的内核需要具有五方面的功能或特性:处理机管理、内存管理、文件系统、设备管理、网络管理。
2.2 Linux在X86 PC机上的启动分析
下面以内核引导程序LILO为例,介绍Linux在X86 PC机上的启动过程。启动过程分为五个阶段:
①加电复位;
②BIOS自举阶段;
③MBR中的LILO的启动;
④Linux内核的运行及系统的初始化;
⑤init进程的运行。
系统加电或复位后,中央处理器将内存中的所有数据清零,并对内存进行校验。如果没有错误,则CS(Code Segment)寄存器中全部置1,而IP(Instruction Pointer)寄存器中全部置0。[CS]:[IP]地址单元中存储的指令是一条跳转指令,这条指令跳转到BIOS代码的首部。CPU就根据CS及IP的值进入BIOS启动过程。
进入BIOS启动后,首先上电自检,完成内存检验、键盘检验、DMA控制器测试、8259中断控制器测试等,然后对系统内的硬件设备进行监测和连接。若检查出致命错误则停机,并显示错误信息。把测试所得数据存放到BIOS的数据区。最后判断磁盘设备是否准备好若无磁盘设备相连或没有主引导记录,则显示出错信息。否则将MBR的Boot Loader调至内存0x07C00处,并将控制权交给Boot Loader。
硬盘的0磁道的第一个扇区称为MBR(Master Boot Recorder),它的大小是512字节。Boot Loader通常是一段汇编代码,存放在MBR中,作用是将系统启动代码读到内存中,LILO(LInux LOader)是一个在Linux环境下编写的Boot Loader程序,可以进行多操作系统的引导。若将LILO安装在MBR中,LILO将完成用户信息的显示、操作系统的选择、命令行参数的传递,然后加载操作系统内核,最后将控制权交给操作系统,由内核完成剩下的工作。
下面系统要做的工作就是顺着启动的代码一步步执行。对于Linux源代码来说启动的代码流程如图1所示:

Bootsect.S用于装载核心系统和setup.S。 setup.S是用汇编语言写的程序代码。Setup.S对已调入内存内核代码进行检查,如果没有错误的话,它会通过BIOS中断获取内存容量信息、设置显示器基本模式、获取硬盘信息,这些操作,都是在X86的实模式下进行的,这时操作系统就准备让CPU进入保护模式。进入保护模式的启动阶段的同时把控制权交给head.S,head.S是段保护模式的汇编程序。Head.S进行页表初始化、检查CPU类型后,调用/init/main.c中的start_kernel()。Start_kernel()用于和处理器、内存等最基本硬件相关部分的初始化、与中断有关的初始化、对Linux文件系统进行初始化。
内核映像一般都是经过压缩的,压缩以后的内核映像就像是一大块数据,跟引导扇区和引导辅助程序的映像拼接在一起,成为内核的“引导映像”。解除压缩以后的内核映像总是放在地址为0x100000(1MB)的地方。Linux核心加载后,由init进程初始化硬件和设备驱动,然后在后台运行init进程。init进程是系统的第一个进程,init进程运行时将用到两个重要的系统引导配置文件/etc/inittab和/etc/rc.d。 inittab描述了在系统初始化时依据不同级别而启动不同的进程。在inittab中首先执行的是/etc/rd.c/rc.sysinit,它的主要功能是检查文件系统、设置硬件设备、检查并载入模块。执行完rc.sysinit并返回inittab后,init进程会依据inittab文件中所设定的启动级别去执行/etc/rc.d目录下相应的rc文件。然后,init进程建立getty进程、NFS守护进程、FTP守护进程。getty进程执行时,等待用户登录。至此,Linux启动成功。
在对Linux内核与嵌入式系统构造相关的部分进行分析之后,下面将分析Linux内核裁减与编译,并使其在X86体系,以CF(compact flash)为存储卡的硬件平台上实现的过程。

3.嵌入式Linux系统的构造

3.1开发环境的建立
由于嵌入式系统资源有限,所以很难在嵌入式系统的硬件平台上进行软件开发。通常解决的方法是在通用计算机上编好程序,通过交叉编译生成可在目标板运行的二进制代码,然后再下载到目标板上的特定位置运行。需要交叉编译环境是嵌入式应用软件开发时的一个显著特点。所谓交叉编译环境是指编译、链接和调试嵌入式应用软件的环境,它与运行嵌入式应用软件的环境有所不同,通常采用宿主机/目标机模式。
在宿主机中安装RedHat9.0操作系统,并装有GCC编译器和Linux内核:linux-2.4.20版本。目标机使用研华PCM3350芯片,基于X86体系,以 CF(compact flash)卡为存储设备。
3.2 Linux内核的裁减与编译
开发环境建立后,就可以针对具体的应用对Linux内核进行裁减。首先在宿主机端进入到内核所在的目录/usr/src/linux-2.4下,修改Makefile文件中EXTRAVERSION 变量的值,用来标识新内核,本例改为hebut。然后完成内核的裁减与编译:
①make mrproper: 用于清除所有的临时文件、中间件、配置文件。
②make xconfig: 进行核心配置,在其中每个选项都有两种选择,分别表示支持和不支持相应的特性或驱动程序,个别选项有‘m’选择,表示把相应的特性或驱动程序编译成可加载模块的方式。根据不同的应用对内核进行裁减。系统将新的配置保存成.config文件。
③make dep: 用于生成依赖性。
④make bzImage: 产生压缩的核心映像。内核压缩映像被系统保留在/usr/src/linux-2.4/arch/i386/boot目录中,将其复制到/boot目录下,并重命名为vmlinuz-2.4.20hebut。末尾为EXTRAVERSION变量的值。
⑤make modules: 组织各个/usr/src/linux-2.4.20子目录已经配置的模块。
⑥make modules_install: 在/lib/modules/2.4.20目录中组织模块。
经过以上的裁减与编译,可以使一个包含网络服务的内核减小到1M以内。
3.3 在CF卡上安装嵌入式Linux操作系统
要在宿主机上将已定制好的内核装入CF卡中并在其上构建操作系统首先需要把CF挂载成宿主机的一个设备。挂载成不同的设备需要不同的连接器。现以把CF卡挂载成USB设备为例,对在其上构建嵌入式Linux操作系统的过程进行介绍。
首先将CF卡进行分区。使用fdisk命令,在CF卡上建立分区。# fdisk /dev/sda1,然后创建ext2文件系统,# mke2fs -c /dev/sda1,该命令在/dev/sda1上创建ext2文件系统。将CF挂载到宿主机上, # mount /dev/sda1 /mnt/sda1,将CF卡挂载到宿主机上后,挂载的目录是/mnt/sda1。
用下面命令创建文件系统:
# mkdir /bin
类似地创建/boot、/etc、/lib、/mnt、/root、/sbin、/tmp、/usr、/var。
用下面的命令创建/dev:
# cp -a /dev /mnt/sda1
这样可以把设备文件创建在CF卡中的/dev目录下。
将生成的压缩内核文件vmlinuz-2.4.20hebut文件放入/mnt/sda1/boot目录下保存。进行以上操作后,需要给CF安装Boot Loader程序使其运行时可以加载内核。Boot Loader是在操作系统内核运行之前运行的一段小程序。通过这段小程序,可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。在嵌入式系统中,通常并没有像 BIOS 那样的固件程序(注:有的嵌入式 CPU 也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由 Boot Loader 来完成。由于研华PCM3350是基于X86体系的,有BIOS的引导,因此同X86 PC机中一样选择LILO为引导程序,在CF卡上启动LILO是使用命令:
# /mnt/sda1/sbin/lilo -r /mnt/sda1 -C etc/lilo.conf
成功后会出现“added Linux *”的提示。使用LILO设置,CF卡就可以启动了。下面是LILO的设置(在/etc/lilo.conf文件中):
boot = /dev/sda
disk = /dev/sda
bios = 0x80
/boot/vmlinuz-2.4.20hebut
root = /dev/sda1
append=“root=/dev/hdc1”

3 结束语

本文在对Linux内核的结构与启动的分析的基础上,介绍了Linux内核裁减与编译的方法,以及向基于X86体系,以CF(compact flash)存储卡的硬件平台上移植的过程。由于Linux操作系统源代码开放,可以免费获得,在嵌入式系统中使用Linux可以极大程度地降低成本,开发后可以拥有自己的版权。Linux操作系统在嵌入式领域将有广阔的发展前景。但为了满足嵌入式系统开发过程人性化的要求与一些系统强实时性的要求,嵌入式Linux在图形化与实时性方面仍有待发展。

参 考 文 献

[1] Karim Yaghmour. Building Embedded Linux Systems. USA: O"Reilly & Associates Inc,2003秦亚杰,周荣政,《一种用于数码相机芯片的CF卡控制电路设计》.《复旦学报(自然科学版)》.2003(2)
[2]魏忠,蔡勇,雷红卫. 《嵌入式开发详解》.北京:电子工业出版社,2003
[3] 2 陈莉君. 《深入分析Linux内核源代码》.北京:人民邮电出版社,2002



上一篇:基于以太网的嵌入式开发环境的研究与实现(ARM+uClinux) 下一篇:基于Linux的实时平台的研究