APP下载

用SD卡定制嵌入式Linux系统的最小系统

2017-11-09,,

单片机与嵌入式系统应用 2017年10期
关键词:单板内核内存

,,

(苏州大学 电子信息学院,苏州 215006)

用SD卡定制嵌入式Linux系统的最小系统

茅胜荣,肖家文,乔东海

(苏州大学 电子信息学院,苏州 215006)

以经典ARM应用处理器S3C6410为例,通过移植u-boot-2013.04-rc2和linux-3.18.57,制作EXT4格式的根文件系统,来定制基于SD卡的嵌入式Linux最小系统,并通过Appweb服务器的移植进一步完善了嵌入式系统的软件功能。实验结果表明,SD卡即插即用的特性大大方便了系统的开发、维护与升级。

S3C6410;嵌入式Linux;U-Boot;EXT4文件系统;Appweb

引 言

在一个完整的嵌入式Linux系统中,Flash扮演着数据与代码存储器的角色,其中NAND类型的Flash具有容量大、成本低的优点,所以很多处理器内部集成了专门的控制器来驱动NAND Flash。但是其工艺决定了它内部容易产生坏块,读写Flash同时需要做额外的ECC校验,这增加了驱动移植的难度。而SD卡利用特殊的封装工艺将NAND Flash颗粒与控制器集成在一起,对外提供高速的SDIO接口进行读写控制,底层驱动程序彻底摆脱了复杂的坏块管理工作。本文在SD卡上搭建U-Boot来引导Linux内核,然后挂载位于SD卡分区上的根文件系统,在此基础上移植嵌入式web服务器Appweb。

图1 配置单板信息

然后将内核从存储介质读取到内存中运行。本文以u-boot-2013.04-rc2为例,分析其移植的一般规律。

1.1 基本配置

U-Boot支持绝大多数CPU体系结构,首先在boards.cfg文件中配置单板计算机的基本信息。如图1所示,单板名字为smdk6410,CPU架构为arm,体系结构为arm1176,制造商为samsung,SoC系列为s3c64xx,U-Boot编译系统通过读取这些信息来筛选需要编译的体系结构相关的源代码。考虑到S3C6410和S3C6400属于一个系列,功能基本相同,因此可以选择U-Boot中的smdk6400作为模板,复制一份相同的源码并重命名,这样可以迅速搭建起一个框架。其次,位于include/configs目录下的smdk6410.h文件中包含了所有板级的配置信息,需要根据实际单板的情况作修改,比如DRAM的大小、命令行提示符等。U-Boot编译系统将单板目录下的u-boot.lds作为默认的链接脚本文件,此外在config.mk文件中指定链接地址的基地址CONFIG_SYS_TEXT_BASE=0x57e0 0000。代码搬移后,u-boot.bin的代码段将从该地址开始,其余段也会根据链接脚本文件确定好在内存中的分布位置。

如图2所示,U-Boot将分多个阶段依次完成最底层的初始化工作,最终创建好Linux内核运行所需要的环境。首先,u-boot.lds文件中的ENTRY(_start)语句指定了u-boot.bin代码段的第一条指令位于start.S文件中的_start标号处,程序直接跳转到reset异常处理代码中运行。在low_level_init函数中,仅需对必需的外设做初始化,比如关闭看门狗、配置系统时钟、初始化调试串口和内存控制器等。

图2 UBoot工作流程

图3所示为SD卡的分区信息,单板上电后,固化在S3C6410内部ROM中的程序会自动把位于SD卡BL1处的代码读取到SRAM中,BL1的主要工作是从SD卡中拷贝完整的u-boot.bin至DRAM中。实际上SRAM的大小只有8 KB,所以必须通过修改u-boot.lds文件来设置代码搬移的程序在u-boot.bin的前8 KB中。代码搬移的工作主要包括SD驱动器初始化、SD卡设备初始化,以及底层I/O的读写驱动。厂商已经把这些功能固化在了ROM中,并且把针对SD卡的拷贝函数的指针存放在0x0C00 4008地址处,函数原型为:

int CopyMMCtoMem(int channel, uint32_t StartBlkAddress, uint16_t blockSize, uint32_t *memoryPtr, int with_init);

其中channel是SD控制器的通道号,StartBlkAddress是待拷贝数据在SD卡上的起始扇区号,blockSize是需要拷贝的扇区数,memoryPtr是拷贝到内存的目标地址,with_init表示是否需要初始化。

图3 SD卡分区信息

Linux内核一般使用低端的内存地址,为了尽可能给内核腾出多的空间,U-Boot会再一次将当前执行的代码搬移到DRAM内存的顶部,这一过程即为重定位,通过汇编函数relocate_code来实现。图4为重定位前后SRAM和DRAM内存的划分情况,重定位前系统堆栈位于SRAM中,破坏了BL1末尾的代码,具有一定的风险。距离DRAM内存底部0x100处存放着Linux内核的启动参数,U-Boot在最后阶段通过do_bootm_linux函数将该地址告知内核,以使内核正确挂载根文件系统。

S3C6410的启动机制表明U-Boot只能烧写在SD卡尾部的特定区域,如图3所示,在偏移SDHC卡末尾521 KB处开始烧写u-boot.bin的前8 KB,这一地址是强制要求的。除此之外的布局可以自定义,但要保证镜像烧写的位置与U-Boot搬移代码时搜索的位置一致。显然,烧写之前必须要获取SD卡总共的扇区数,Linux下使用fdisk-l命令可以查看当前SD卡所有的信息,然后通过简单的字符串处理便能提取出SD卡总共的扇区数,具体脚本如下:

TOTAL_BLKCNT=`sudo fdisk-l $FLASH_MEDIA|head-n 1|awk ‘{print $7}’`

其中FLASH_MEDIA变量代表SD卡的设备文件名,通常为/dev/sdx,x可以是a,b,c,d等。

为了方便烧写,需要把BL1和BL2两个部分拼在一起制作成U-Boot刷机包,步骤如下:

① 创建空白镜像:dd if=/dev/zero of=$LOADER bs=1K count=$LOADER_SIZE。

② 把镜像文件设置为回环设备:sudo losetup /dev/loop0 $LOADER。

③ 拼接BL1与BL2:sudo dd if=u-boot.bin of=/dev/loop0 bs=1k seek=0和sudo dd if=u-boot.bin of=/dev/loop0 bs=1k seek=528 count=8。

④ 卸载回环设备:sudo losetup -d /dev/loop0。

图4 SRAM与DRAM的内存划分

脚本中的LOADER和 LOADER_SIZE代表U-Boot刷机包的名字和大小。最后将刷机包烧写进SD卡设备:

sudo dd if=$LOADER of=$FLASH_MEDIA bs=1k count=$LOADER_SIZE seek=$SEEK_OFFSET

其中SEEK_OFFSET的值可以通过表达式`expr $TOTAL_SIZE - $LOADER_SIZE`来求得。图5所示为最终烧写在SD卡中的U-Boot启动界面,因为SD卡中还未烧写环境变量,因此U-Boot警告bad CRC,将使用U-Boot代码中默认的环境变量。

图5 UBoot启动界面

2 Linux内核移植

U-Boot启动后,在没有检测到用户终端输入的情况下会自动执行环境变量bootcmd中的指令,其具体内容定义在全局配置文件smdk6410.h中:

#define CONFIG_BOOTCOMMAND "fatload mmc 0:2 50008000 uImage; bootm 50008000"。

U-Boot通过fatload命令将SD卡第二个分区上的uImage文件读取到内存0x5000 8000处,然后程序跳转到该地址运行Linux内核。本文以linux-3.18.57为例,分析内核镜像uImage制作的一般规律。

2.1 基本配置

内核的移植非常复杂,不可能一步到位,可以先移植出一个基本能用的内核,再逐步向其中添加新的功能,直至内核最终能够驱动开发板上所有设备。Linux内核支持的使用S3C6410芯片的单板非常多,这里选择友善之臂的MINI6410作为模板。将板级初始化文件mach-mini6410.c重命名为mach-suda6410.c,并将文件中所有的mini(MINI)修改为suda(SUDA)。将mach-suda6410.c编译进内核中,需要由Kconfig和Makefile配合完成,即在Kconfig中加入config MACH_SUDA6410条目,并且在Makefile中添加编译选项:obj-$(CONFIG_MACH_SUDA6410) += mach-suda6410.o。这样就能通过make menuconfig选中SUDA6410来把文件编译到内核中。图6为U-Boot和内核对机器码的定义,一个U-Boot只能引导一种单板,两者之间使用机器码来匹配。U-Boot在do_bootm_linux函数中会将机器码作为参数传递给内核,内核会尝试引导该机器码对应的单板,一旦不匹配,将停止加载。

嵌入式Linux通常需要一个完整的网络环境,Linux内核不仅具有成熟稳定的网络协议栈,还支持各种主流的网卡驱动。图7为网卡配置界面,通常只需要在内核配置中添加对网络子系统的支持,并选择实际使用的网卡对应的驱动,就可以使单板具备入网功能。

2.2 制作uImage

make menuconfig结束后,会生成.config文件,保存着有关内核的所有配置选项,make命令将根据它来指导内核编译系统的工作,并最终生成zImage镜像文件。U-Boot的bootm命令无法直接加载zImage,需要使用mkimage工具给zImage额外增加64字节的头部信息,具体使用方法为:

mkimage -A arm -O linux -T kernel -C none -a 50008000 -e 50008040 -n "$KERNEL_NAME"-d zImage uImage

图6 机器码

图7 网卡配置选项

其中-A指定CPU的体系结构,-O指定操作系统类型,-T指定镜像类型,-C指定镜像的压缩方式,-a指定uImage在内存中的加载地址,-e指定镜像运行的入口点地址,-n指定镜像名字,-d指定zImage的路径。

2.3 烧写uImage到SD卡

uImage的烧写不同于U-Boot,它是一个分区+格式化的过程,由图3可知,uImage保存在SD卡的第二个分区上。U-Boot的fatload命令只能识别vfat格式的分区,因此需要将该分区格式化成vfat,具体烧写步骤如下:

① SD卡分区:sudo fdisk $FLASH_MEDIA和sudo partprobe $FLASH_MEDIA。

② 格式化内核分区:sudo mkfs.vfat $FLASH_MEDIA$KERNEL_PART。

③ 挂载内核分区:sudo mount -t vfat $FLASH_MEDIA$KERNEL_PART /mnt。

④ 烧写uImage:sudo cp $KERNEL_OUTPUT/uImage /mnt。

⑤ 卸载内核分区:sudo umount /mnt。

3 根文件系统制作

内核启动的最后阶段会根据设置的启动参数挂载对应的根文件系统,最后运行根文件系统中的init用户进程。

3.1 内核启动参数

内核的启动参数保存在U-Boot的bootargs环境变量中,也可以在smdk6410.h文件中进行设置:

#define CONFIG_BOOTARGS "root=/dev/mmcblk0p1 rootfstype=ext4 rootwait=5 console=ttySAC0,115200 init=/linuxrc"

其中的rootfstype参数指定根文件系统的类型,root参数指定根文件系统所挂载的物理设备,console参数指定用户终端设备,init参数指定内核启动的第一个用户进程在根文件系统中的路径。

3.2 构建最小根文件系统

要构建一个可用的根文件系统,需要按照FHS(Filesystem Hierarchy Standard)的标准布局文件目录,并且创建必要的二进制文件和库文件。Buildroot是一个简单高效,用于定制嵌入式Linux文件系统的工具,底层封装了很多busybox软件的配置工作。如图8所示,通过make menuconfig对Buildroot进行配置,Target options菜单中是与体系结构相关的配置选项,System configuration菜单中是用户系统相关的配置选项,Toolchain菜单中是交叉编译工具的配置选项。此外,还可以在Target packages中选择常用的第三方应用程序包。尽管Buildroot能够生成一个完整的根文件系统,但仍然需要微调,例如,Linux系统的启动需要/dev/null文件,可以通过sudo mknod/dev/null c 1 3来创建这个设备文件。再如为了提高mdev生成设备文件的速度,推荐以ramfs方式挂载/dev目录,即mount-t ramfs mdev/dev。

图8 Buidroot配置

3.3 烧写根文件系统到SD卡

根文件系统存放在SD卡的第一个分区。Linux内核最常使用的文件系统是EXT4,属于日志型文件系统,它使用独立的日志文件跟踪磁盘内容的变化,比传统文件系统安全。烧写EXT4格式的文件系统到SD的主要步骤如下:

① SD卡分区:sudo fdisk $FLASH_MEDIA和sudo partprobe $FLASH_MEDIA。

② 格式化文件系统分区:sudo mkfs.ext4 $FLASH_MEDIA$ROOTFS_PART。

③ 挂载文件系统分区:sudo mount $FLASH_MEDIA$ROOTFS_PART /mnt。

④ 烧写文件系统:sudo tar-vxf $ROOTFS_OUTPUT/rootfs.tar-C/mnt。

⑤ 卸载文件系统分区:sudo umount/mnt。

图9展示了Linux内核与文件系统的运行结果,通过命令uname -a可以查看到当前内核的版本和名字。

图9 Linux内核与文件系统的运行结果

4 Appweb移植

在某些应用场合下,Buildroot无法提供所有需要的第三方软件包,这就需要从源代码编译安装到文件系统中。本文以开源的嵌入式web服务器Appweb为例,分析移植第三方库的一般规律。Appweb针对嵌入式设备进行高度优化,能够提供高能效、高吞吐率的动态网页应用。Appweb的编译安装需要使用MakeMe工具,这是一种扩展了Makefile的项目管理与编译自动化技术。Appweb移植的具体步骤如下:

① 配置源码:./configure--show--nolocal--release--platform linux-arm-release。

② 编译源码:me--overwrite。

③ 安装与发布:me--deploy deploy2ARM。

最后把deploy2ARM中的所有内容拷贝到文件系统相应的目录中,便完成了Appweb的移植工作。在单板的用户终端输入命令appweb --config appweb.conf启动

图10 Web服务器运行结果

服务器,其中appweb.conf是针对该服务器的配置文件,可以指定服务器监听的端口号,网页内容的根目录等。图10所示是通过浏览器访问该服务器返回的页面,该网页仅仅测试了Web服务器的最小功能。

结 语

[1] 杨铸,李奎.构建嵌入式Linux核心软件系统实战[M].北京:北京航空航天大学出版社,2013.

[2] 朱兆琪,李强.嵌入式Linux开发实用教程[M].北京:人民邮电出版社,2014.

[3] 范展源,刘韬.深度实践嵌入式Linux系统移植[M].北京:机械工业出版社,2015.

[4] 周立功.嵌入式Linux开发教程[M].北京:北京航空航天大学出版社,2016.

[5] Embedthis Software.APPWEB DOCS [EB/OL].[2017-06].https://embedthis.com/appweb/doc/.

茅胜荣、肖家文(在校研究生),研究方向为嵌入式系统设计、信号处理;乔东海(教授),研究方向为信号处理、MEMS器件设计。

[5] WANG Nan,MENG Qingfeng,ZHENG Bin.Data compression and coding algorithm used in wireless transmission of vibration signal[J].Journal of Vibration,Measurement &Diagnosis,2013,33(2):236-241.

[6] Kutyniok G.Compressed Sensing:Theory and Applications[J].Corr,2012,52(4):1289-1306.

[7] 杨真真.压缩感知重构技术及其在图像融合中的应用研究[D].南京:南京邮电大学,2014.

[8] 方亮.基于压缩感知的无线传感器网络数据压缩算法研究[D].长沙:湖南大学,2011.

[9] 王小雪.基于无线传感器网络的无源被动式目标定位研究[D].杭州:浙江工业大学,2013.

[10] 陈剑美.压缩感知算法的改进及其在无线传感网络中的应用[D].秦皇岛:燕山大学,2016.

邵云峰,主要研究方向为无线传感器网络。

EmbeddedLinuxMinimalSystemCustomizedwithSD

MaoShengrong,XiaoJiawen,QiaoDonghai

(Department of Electronic Information,Soochow University,Suzhou 215006,China)

In the paper,taking the classic ARM processor S3C6410 for example,The customize embedded Linux minimal system based on the SD card is introduced by porting u-boot-2013.04-rc2 and linux-3.18.57,and the root file system formatted in EXT4 is built.The embedded web server called Appweb makes the system more powerful in software.The experiment results show that the plug-and-play feature of SD card greatly facilitates the development,maintenance and upgrading.

S3C6410;embedded Linux;U-Boot;EXT4 file system;Appweb

TP368.2

A

2017-06-30)

(责任编辑:薛士然 收稿日期:2017-06-15)

猜你喜欢

单板内核内存
强化『高新』内核 打造农业『硅谷』
外部高速缓存与非易失内存结合的混合内存体系结构特性评测
单板U型场地滑雪关键技术动作及训练方法
“春夏秋冬”的内存
基于嵌入式Linux内核的自恢复设计
Linux内核mmap保护机制研究
单板层积材带来的内部生产模式
微生物内核 生态型农资
封面人物 单板滑雪凌空飞燕蔡雪桐
基于内存的地理信息访问技术