步入后PC时代以来,伴随着设计和制造技术的发展,集成电路从先前的晶体管集成发展到如今的IP集成,即SoC(SystemonChip)设计技术。使得嵌入式系统渗透到了现今社会中的各个行业,但是发挥越来越重要的作用。嵌入式系统通常可定义为以应用为中心、以计算机技术为基础、软硬件可剪裁、适用于应用系统且对功能、成本、体积、功耗有严格要求的专用计算机系统,它的主要特征是嵌入、应用。
随着各类嵌入式设备功能越来越强悍,在设备中使用嵌入式操作系统也成为必然。Linux操作系统具有开放源代码、易于移植、资源丰富、免费等特性,在嵌入式领域的地位越来越重要。嵌入式Linux和PC上的Linux是同一套内核代码,只是剪裁的程度不一样,所以,好多在PC上开发的软件,经过交叉编译后可以直接在嵌入式设备上运行。本文主要涉及到Bootloader移植和Linux-2.6.32.2内核的移植、根文件系统移植、在S3C2440平台上建立完整的嵌入式开发平台三个方面。
1交叉开发环境的构建
在进行嵌入式软件开发之前,必需要在PC上构建ARM的交叉编译环境。交叉编译就是在PC平台上生成可以在ARM平台上运行的代码。其中主要包括ARM的交叉编译器arm-elf-gcc和交叉联接器arm-elf-ld。本文采用的交叉编译器的版本是gcc-3.4.5-glibc-2.3.6。
交叉编译流程如图1所示。
图1嵌入式系统交叉编译流程
2BootLoader引导加载程序
BootLoader是一段在系统上电时开始执行的程序,用以初始化硬件设备,打算好软件环境,设置好启动参数,最后引导操作系统,与PC上的BIOS程序相像。当前开放源码的Linux引导程序主要有x86构架的LILO、GRUB,对于ARM构架的主要有Vivi和U-Boot。本文使用U-Boot作为引导程序。U-Boot(UniversalBootLoader),即通用的BootLoader,遵守GPL条款开放源代码。U-Boot相对于Vivi功能更强化大,也更便捷后续程序的调试。
BootLoader的启动通常分为两个阶段,第一阶段的代码主要是用汇编语言编撰arm linux内核启动流程,主要的功能是完成硬件设备的初始化,为加载第二阶段的代码打算RAM空间,设置好堆栈;第二阶段主要用C语言编撰,测量显存映射,将内核映像和根文件系统从NandFlash读到RAM中,为内核启动设置参数,引导内核。
U-Boot的源代码可以从ftp://ftp.denx.de/pub/u-boot/进行下载,本文使用的U-Boot版本是U-Boot2009.08。
移植U-Boot的关键步骤如下:
(1)首先,将include/configs目录下的smdk2410.h复制并更名为mini2440.h,按照U-Boot的说明可以晓得,假如要使用开发板board/,则先执行“make”_config命令进行配置,之后执行“makeall”,生成可执行文件。所以,更改U-Boot顶楼的Makefile文件,添加下边一行mini2440_config:unconfig@$(MKCONFIG)$(@:_config=)armarm920920tmini2440franks3c24x0。这儿有几个重要的参数,arm指CPU的构架,arm920920t指CPU的类型,s3c24x0指CPU的机型。这样就可以使用makemini2440_config这条命令进行配置。
(2)本文使用的U-Boot是从NandFlash启动的,CPU可以直接访问NandFlash中前4KB代码,借助这4KB代码把U-Boot中绝大部份代码拷贝到显存中[3]。其中下边的代码就是调用C语言中的NandFlash的读写函数,该函数主要把NandFlash中4KB之后的代码复制到RAM中。在编撰nand_read_ll的函数时,注意参考NandFlash的数据指南,对大页和小页的NandFlash,其读写的命令和时序是不同的。
@copyU-BoottoRAM
ldrr0,=TEXT_BASE
movr1,#0x0
movr2,#0x60000
blnand_read_ll
tstr0,#0x0
beqok_nand_read
因为在前面加载Linux内核和根文件系统时,使用的是tftp形式,所以必须添加DM9000EP网卡的驱动。在mini2440.h文件中,其主要的配置如下:
#defineCONFIG_DRIVER_DM90001
#defineCONFIG_NET_MULTI1
#defineCONFIG_DM9000_NO_SROM1
#defineCONFIG_DM9000_BASE0x20000300
#defineDM9000_DATA(CONFIG_DM9000_BASE+4)
其中虚拟主机 linux,CONFIG_DM9000_BASE宏是最重要的,由于它定义的是网卡的地址,不同的网卡有不同的地址,DM9000EP访问的基址为0x20000000,之所以再偏斜0x300是由它的特点决定的。
(3)要正确引导Linux内核,还须要配置下边几个重要的宏定义,这几个宏定义不同,意味着引导Linux内核的形式也不同。
#defineCONFIG_BOOTARGS"noinitrdroot=/dev/mtdblock3
init=/linuxrcconsole=ttySAC0,115200mem=64M"
其中,root=/dev/mtdblock3是由Linux中的NandFlash分区所决定的,意味着NandFlash的第4个分区为根文件系统。
#defineCONFIG_BOOTCOMMAND"nandread0x320000000x600000x560000;bootm0x32000000"
这个宏定义是将NandFlash中0x60000-0x560000(和kernel分区一致)的内容读到显存0x32000000中,之后用bootm命令来执行。
要正常地引导Linux内核,必需要具备如下几个条件:
(1)CPU寄存器
R0=0;
R1=机器类型ID;对于ARM结构的CPU国内linux主机,其机器类
型ID在linux/arch/arm/tools/mach-types;
R2=启动参数标记列表在RAM中起始基地址。
(2)CPU工作模式
必须严禁中断(IRQs和FIQs);
CPU必须为SVC模式。
(3)Cach和MMU的设置
MMU必须关掉;
指令Cach可以打开也可以关掉;
数据Cach必须关掉。
3Linux2.6.32.2内核的移植
3.1内核的获取
Linux内核的更新很快,可以从得到最新的Linux内核版本,本文使用的Linux内核版本是Linux-2.6.32.2,交叉编译工具使用符合EABI标准的arm-linux-gcc-4.3.2。
3.2内核的移植
可以在内核的根目录下,运行makemenuconfig命令,对内核进行适当的剪裁,以适应硬件平台。
对内核进行适当的剪裁,以适应硬件平台。
(1)更改Makefile文件
欲设置Linux的默认平台为ARM平台,需步入Linux-2.6.32文件夹中,更改此目录下的Makefile文件。
exportKBUILD_BUILDHOST:=$(SUBARCH)
ARCH?=arm//使用的目标平台
CROSS_COMPILE?=arm-linux-//使用的交叉编译器,
这儿使用系统默认的编译器
(2)关于机器码
在启动内核时,按照BootLoader传入的机器码(MACH_TYPE)来决定应启动哪种目标平台[6],本开发平台的机器码为1999。机器码储存在文件opt/kernel/linux-2.6.32.2/arch/arm/tools/mach-types中。
mini2440MACH_MINI2440MINI24401999//机器码
假如机器码不匹配,引导内核不成功,则会出现如下的错误提示:
Uncompressing
Linux……………………………………………………………………………done,bootingthekernel.
(3)更改时钟源
将/kernel/linux-2.6.32.2/arch/arm/mach-s3c2440/目录下的mach-smdk2440.c文件更名为mach-mini2440.c。
由于mini2440和mach-smdk2440.c十分相像,以该文件为基础进行更改,在mach-mini2440.c文件上将staticvoid__initsmdk2440_map_io(void)函数中的晶振频度更改为mini2440开发板上实际使用的12000000。
(4)为内核打上yaffs2补丁
①Yaffs2文件系统是专门针对嵌入式设备,非常是使用NandFlash作为储存器的嵌入式设备而创建的一种文件系统,使用yaffs2就可以支持大页的NandFlash。
步入yaffs2源代码目录执行如下命令:
#./patch-ker.shc/opt/FriendlyARM/mini2440/linux-2.6.32.2
②配置内核以支持Yaffs2文件系统
在Linux内核源代码根目录运行makexconfig,在“Filesystems”选项中,找到“Miscellaneousfilesystems”菜单项,找到“YAFFS2filesystemsupport”并选中它,这样就在内核中添加了yaffs2文件系统的支持,保存并退出。之后在命令行中,执行makezImage。
(5)更改NandFlash分区信息
①在mach-mini2440.c文件中添加NandFlash的分区信息,下边的代码将NandFlash分成了4个分区,第1分区也是BootLoader所在的分区,对应dev/mtdblock0;第2个分区是U-Boot的参数分区,对应dev/mtdblock1;第3个分区是内核分区,对应dev/mtdblock2;第4个分区为根文件系统分区对应dev/mtdblock3。分区结布光如表1所示。
表1128MBNandFlash的分区结布光
其部份实现代码如下:
staticstructmtd_partitionmini2440_default_nand_part[]={
[0]={
.name="U-boot",
.offset=0,
.size=0x00040000,
其中name是分区的名子,offset是偏斜的开始地址,size是分区的大小,其余部份的分区与此类似。
②下面代码是添加NandFlash的设置表,由于板子上只有一片NandFlash,因而也就只有一个设置表。
staticstructs3c2410_nand_setmini2440_nand_sets[]={
[0]={
.name="NAND",
.nr_chips=1,
.nr_partitions=
ARRAY_SIZE(mini2440_default_nand_part),
.partitions=mini2440_default_nand_part,
③上面的设置完成后,还须要将NandFlash设备注册到系统中。下边这段代码就是将NandFlash设备添加到开发板的设备列表结构。
staticstructplatform_device*mini2440_devices[]__initdata
={
&s3c_device_nand,
④在mini2440_machine_init函数中添加平台的数据信息。
staticvoid__initmini2440_machine_init(void){
s3c_device_nand.dev.platform_data=&mini2440_nand_info;
如今可以步入kernel/linux-2.6.32.2/arch/arm/boot目录,之后执行下边的命令,都会在该目录下生成uImage.img格式的、U-Boot可以引导的内核存盘。
Mkimage–n‘linux-2.6.32.2’–Aarm–Olinux–Tkernel–Cnone–a0x30008000–e0x30008000–dzImageuImage.img
至此,可以把生成的uImage.img格式的镜像文件复制到tftp目录下,使用tftp进行下载。
3.3文件系统
所谓根文件系统,就是创建各个目录,比如在/bin、/sbin/目录下储存各类可执行的程序,在/etc目录下储存配置文件,在/lib目录下储存库文件。
可以借助Busybox工具创建根文件系统,Bosybox是一个遵守GPLv2合同的开源项目,它在编撰过程中对文件大小进行优化arm linux内核启动流程,并考虑了系统资源有限(比如显存)的情况,使用Busybox可以手动生成根文件系统所需的bin、sbin、usr目录和linuxrc文件,可以使用makemenuconfig对Busybox的选项进行配置。
(1)步入opt/kernel,创建一个shell脚本用于建立根文件系统的各个目录,但是为其降低执行权限;(2)Linux中的init进程会依照etc/inittab文件创建其他子进程,下边代码是inittab文件中的内容,说明了系统启动后首先执行的脚本文件是rcS,虚拟的终端是并口0,当按下ctr+alt+del时重启系统,inittab文件的作用就是控制系统启动时和启动后一些程序的运行。
#etc/inittab
::sysinit:/etc/init.d/rcS
s3c2410_serial0::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount-a-r
(3)创建etc/init.d/rcS文件,这是一个脚本文件,可以在上面添加要手动执行的一些命令。
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S//运行的级别
prevlevel=N
umask022//文件夹的网段
mount-a//挂载/etc/fstab/文件指定的所有的文件系统
mdev-s
/bin/hostname-F/etc/sysconfig/HOSTNAME//主机的名子
使用yaffs源码提供的工具制做文件系统的映像文件。因为128MB的NandFlash是大页结构,所以须要使用相应的大页制做工具;使用命令mkyaffs2imagerootfsrootfs.img生成根文件系统映像文件。
本文通过对U-Boot移植和Linux内核移植的讨论,给出了移植U-Boot和Linux到大多数开发板的关键部份。因为移植的复杂性,不可能包括全部步骤,但通过本文的论述可以了解移植的基本流程和关键点,为移植不同版本到其他硬件平台提供了参考,也为应用程序的开发搭建了一个比较完整的嵌入式平台。