摘 要:EasyARM2200开发板仅有512KB RAM和2MB FLASH存储器资源,能否运行uClinux以及如何运行 uClinux,是喜爱这款开发板的技术人员一个共同的心声。本文通过分析uClinux的内存管理和内核引导机制,介绍了uClinux2.4针对EasyARM2200开发板的移植和改造方法。
关键词:EasyARM2200、移植uClinux
1. 引 言
EasyARM2200是广州周立功公司设计开发的一款32位ARM开发板,该板采用了PHILIPS公司总线开放的ARM芯片LPC2210,板上集成了键盘、LED、蜂鸣器、AD转换等单元电路,并且对外提供了RS232通讯接口、modem通讯接口、USB通讯接口、存储卡接口、以太网接口等功能部件[1],非常方便用户进行开发试验,深受广大开发人员的喜爱。
在EasyARM2200开发板上运行uClinux有两个主要的工作要做,一是增加uClinux 对LPC2210处理器的支持;二是裁减和改造uClinux,使它能在开发板上运行。关于LPC2210处理器的移植工作,我们可以参照uClinux 针对其它处理器的移植方案,重点分析硬件部分的差异。第二项工作则需要我们彻底分析uClinux 的内存管理以及它的内核运行机制。
2. uClinux 分析
2.1 uClinux 简介
uClinux专门针对没有内存管理单元的CPU,并且专为嵌入式系统做了许多小型化的工作,目前已经被广泛移植到了众多的32位微处理器。作为linux的一个分枝,uClinux 的版本也从2.0、2.2、2.4一直发展到现在最新的2.6,而且2.6版本已经成为了linux2.6 发行版的一个部分。
2.2 uClinux 内存管理机制
uClinux 不支持虚拟内存管理技术,但它和linux一样采用分页管理机制。系统在启动的初始化阶段对内存进行分页,并且标记已使用的和未使用的内存。在每一个 uClinux 进程被创建前,内核的执行文件加载器对uClinux采用的 flat 文件进行处理,选择全部加载或只加载数据。如果没有足够的内存页面,内核将试图释放一些页面供该进程使用。当然,如果释放不出足够的空间,uClinux 将陷入一个死循环。所以在编译内核前,开发人员必须告诉系统这块开发板到底拥有多少内存,并规划好内存资源的分配[2]。
2.3 uClinux 内核引导
系统上电后,程序计数器 (PC) 指针指向地址0x00处执行系统引导程序, 在建立内核的运行环境后,跳转到内核起始位置, 开始内核的引导过程。内核的引导程序是 uClinux-dist/linux-2.4.x/init/main.c中的start_kernel()函数,它在进行一系列的初始化过程后,启动init 进程。这个进程调用init()函数,在init() 函数中执行rc脚本输出uClinux 启动字样,运行Sash 程序建立 shell 命令行。整个系统引导的流程图如图1所示:
图1 uClinux 启动流程图
3. uClinux 对 LPC2210 的支持
linux.2.4.X/arch 下的每个子目录代表移植到uClinux 环境下的不同的处理器体系结构。armnommu目录表示的是无 MMU 的ARM 芯片。因为LPC2210 也属于ARM 体系,所以我们要做的工作就是添加及修改与 LPC2210处理器硬件相关的细节。限于篇幅,移植细节在这里不作介绍,只在下表列出需要修改的文件:
表 1 移植到LPC2210需要修改的文件
文 件 及 目 录 修 改 内 容
arch/armnommu/config.in 添加 CONFIG_ARCH_LPC 项
arch/armnommu/tools/mach-types 添加 LPC2210 体系结构定义
arch/armnommu/mm/proc-arm6,7.S 添加 LPC2210 芯片的硬件信息
arch/armnommu/kernel/entry-armv.S 添加 LPC2210 中断部分宏定义
linux-2.4.x/Arch/Armnommu/mach-lpc 添加 LPC2210 目录
(续上表)
include/asm-armnommu/arch-lpc/hardware.h 添加 LPCC2210 头文件
arch/armnommu/kernel/head-armv.S 添加 关于 LPC2210 的启动部分
arch/armnommu/mach-lpc/arch.c 添加 LPC2210 结构定义
arch/armnommu/mach-lpc/irq.c 添加 关于LPC2210中断管理部分
arch/armnommu/mach-lpc/Makefile 添加 makefile 文件
armnommu/Makefile 定义内核开始地址
drives/block/blkmem.c 修改 ROMFS 的地址
uClinux-dist/vendors/PHILIPS/lpc2200/rc 修改启动脚本
4. uClinux 针对EasyARM2200 的裁减和改造
4.1 设计 Bootloader
Bootloader 是系统加电后运行的系统引导代码,它完成基本的硬件设备的初始化,并负责加载和引导内核,为uClinux 的运行建立一个合适的软硬件环境[3]。
uClinux2.4.x\arch\arm\armnommu\boot\compressed\ head.s 是 uClinux 自带的一个 Bootloader 程序,但它把内核和文件系统都加载到RAM 空间中运行,这样做的目的是为了提高程序的运行速度,但却加大了对内存的开销,不适用于我们的开发板系统。所以我们需要自行设计一个简单、高效的Bootloader 来实现开发板的初始化和 uClinux 的引导。
图2 BootLoader 程序流程图
4.2 选择内核形式
uClinux 根据不同的配置,可以生成以下几种不同的内核形式[4]:
4.1.1 非压缩,非XIP
XIP(eXecute In Place)是指代码可在存放的位置直接运行;而非XIP是指在运行之前需要对代码进行重定位。该类型的 Kernel Image以非压缩格式存放在Flash中,需由Bootloader加载到RAM 中运行。
4.1.2 非压缩,XIP
该类型的 Kernel Image以非压缩格式存放在Flash中,不需加载,由Bootloader直接调用。复制Data段和清零BSS段的工作由Kernel自行完成。
4.1.3 RAM自解压
压缩格式的 Kernel Image由开头的一段自解压代码和其后的压缩数据组成。在被 Bootloader 加载到RAM中的临时空间后,调用其自解压代码把 Kernel 解压到目标空间。
4.1.4 ROM自解压
该类型的 Kernel Image存放在Flash中,不需加载。由 Bootloader直接调用其自解压代码把Kernel 解压到目标空间。
一般的uClinux 选择 “RAM 自解压”方式,压缩的Kernel Image 放在ROM 空间,而解压后的内核在RAM空间运行。显然,EasyARM2200开发板不能采用这种方式,而应该采用“非压缩,XIP”方式,把内核代码放在板上 Flash 空间中直接运行,从而减少对RAM 的开销。
4.3 采用 ROMFS 作为根文件系统
uClinux 启动后,根据启动参数加载根文件系统即 ROOT 文件系统。uClinux2.4 默认的启动参数为“ROOT = RAM0”,即采用 RAMFS 作为根文件系统。顾名思义,RAMFS 是一种内存文件系统,它工作于虚拟文件系统(VFS)层。对于EasyARM2200 开发板来说,由于其内存资源非常有限,因而不能采用RAMFS文件系统。而ROMFS 文件系统是一种可以在 FLASH 上直接运行的文件系统,它需要的代码空间较小,在运行时对内存的开销也较小,所以我们选择 ROMFS作为根文件系统。
4.4 存储空间分配
合理规划开发板存储资源的分配是运行 uClinux 的关键。首先需要实现 uClinux 内核中的.INIT段、.TEXT段、.DATA段和 .BSS段在存储空间的重新定位,我们可以通过修改Linux2.4.x\arch\armnommu 目录下的 mlinux-armv.lds来实现这个目的。
.TEXT是 uClinux 内核代码段,我们把它定位在 FLASH 地址空间;.DATA段是 uClinux 被初始化的数据空间,.BSS段是 uClinux没有被初始化的数据空间,由于它们都是可读写数据段,所以必须定位在 RAM 空间;.INIT段是所有.INIT初始化代码的程序和数据段,由于它在初始化完成后被系统收回,所以也可定位在RAM 空间。
EasyARM2200开发板FLASH地址空间为0x80000000—0x80200000,系统上电后,其起始地址被映射为地址0x00,因此0x80000000位置必须存放Bootloader代码;从0x80008000处开始存放内核影像文件image.bin;而在地址0x80080000处存放文件系统影像文件romfs.img。
开发板 RAM地址空间为0x81000000—0x81080000,主要是内核运行所需要的数据段和任务进程使用。由于内核把内核空间以下的16K 内存存放页表,所以我们把内核数据段定位在0x81008000处。
4.5 重新配置内核
重新配置内核,是裁减 uClinux 一个主要的方式。通过 make menuconfig 或 make config,可以选择我们需要的选项,从而去掉不需要的功能和模块,达到减少存储空间开销的目的。以下是针对EasyARM2200开发板的uClinux 配置方案:
4.5.1 System Type 是针对不同处理器的选项,我们选择移植时增加的 CONFIG_ARCH_LPC 项;
4.5.2 CONFIG_SET_MEM_PARAM 是针对不同存储器配置的选项,这里我们根据EasyARM2200开发板资源,配置为:
DRAM_BASE=81000000,DRAM_SIZE=00080000
FLASH_MEM_BASE=80000000,FLASH_SIZE=00200000
4.5.3 CONFIG_CMDLINE_BOOL 是启动参数项,这里我们指定FLASH为根设备: CONFIG_CMDLINE="root=/dev/rom"
4.5.4 CONFIG_ROMKERNEL=Y,选择“非压缩,XIP ”内核形式
4.5.5 File System 是文件系统选项,选择 ROMFS:
CONFIG_ROMFS_FS = Y
4.5.6 Block Device 是和文件系统相关的块设备,这里选:
CONFIG_BLK_DEV_BLKMEM = Y
4.5.7 Net Devices 是网络设备选项, 虽然网络是linux的长项,但在非网络应用时,也可以不选此项。
4.5.8 Application 是应用程序选项,这里,我们只选择两个最基本的选项:
CONFIG_USER_INIT_INIT = Y
Enable Console Shell = Y
CONFIG_USER_SASH_SH = Y
这样,可保证 uClinux 拥有init 进程和一个 shell 命令行界面。
5. 运行 uClinux
移植后的uClinux 经编译后,生成的内核影象文件 image.bin 大小为425KB,生成的文件系统影象文件 romfs.img大小为150KB,再加上3K的BootLoader,整个系统占用的ROM 空间大约630 KB。用FLASH 烧写工具依次将 Bootloader、image.bin 及 romfs.img 烧写到 FLASH 中相应位置,然后就可以启动运行uClinux 系统了。
6. 结论
实践证明,EasyARM2200 开发板能够运行 uClinux,但是在系统相对复杂时,比如加入网络支持等,其512KB RAM 空间还是显得不足,此时必须更进一步优化和改造其内核,才能满足实际的需要。希望本文能给 uClinux爱好者起到抛砖引玉的作用,为 uClinux 在嵌入式系统中的应用拓展更大的空间。
参考文献
[1] 周立功等. ARM与嵌入式系统实验教程. 广州: 广州周立功有限公司, 2004.11
[2] 邹思轶. 嵌入式Linux设计与应用. 北京: 清华大学出版社, 2003.2
[3] 李善平,刘文峰,王焕龙.Linux与嵌入式系统.北京:清华大学出版社,2003.1
[4] 詹荣开. 嵌入式系统Boot Loader 技术内幕[EB/OL]. http://www-128.ibm.com/developerworks/cn/linux/l-btloader/index.html. 2003.12.01
[5] Ryan Sheng. Porting uClinux to Samsung S3C44B0X Board[EB/OL].
http://www.linuxforum.net. 2004.09.07