uClinux在嵌入式系统中的移植研究

时间:2022-05-01 20:08:46
作者:苏义鑫,王子毅,张素文    时间:2007-04-28  来源:    

摘要:uClinux是针对微控制领域而设计的Linux操作系统,继承了Linux的众多优点,广泛应用于嵌入式系统中。针对不同的嵌入式处理器移植uClinux已成为嵌入式系统研究的一个重点。本文选择以三星公司生产的S3C44B0处理器为核心的硬件平台,详细介绍uClinux移植到S3C44B0的方法和过程。

关键词:嵌入式系统;uClinux;移植;ARM

引言

uClinux作为Linux衍生操作系统,具有支持多任务、内核精简、高效、稳定和源代码开放等优点,专门应用于无MMU微处理器的嵌入式系统。将uClinux应用于嵌入式系统已经成为许多嵌入式开发人员的选择。本文针对基于三星公司生产的ARM系列微处理器S3C44B0的硬件平台,详细论述移植uClinux的过程,主要包括BootLoader的设计,uClinux内核的修改,交叉编译环境的建立,uClinux内核的配置,编译及连接,映像文件的下载及运行。

硬件环境

硬件平台以S3C44B0为核心,采用的外部晶振频率为10MHz,内核主频最高可达到64MHz;通过RS232接口与上位机通讯;外接JTAG接口,支持在线调试;采用SST39VF1601(2M字节)作为程序存储器,对应的地址空间为0x00000000-0x001fffff;采用HY57VF641620(8M字节)作为数据存储器,对应的地址空间为0x0c0000000x0c7fffff。硬件框图如图1所示。

uClinux在嵌入式系统中的移植研究
图1 硬件框图

uClinux的移植

移植思路
硬件环境确定以后,首先,要为uClinux设计一个BootLoader,通过BootLoader来初始化硬件,引导uClinux运行。Bootloader设计可以在ads中实现。然后,针对硬件环境,和设计的BootLoader修改uClinux内核。接下来,在Linux操作系统下建立编译uClinux的交叉编译环境。最后,配置、编译、连接uClinux,下载编译得到的映像文件到Flash,通过BootLoader来启动uClinux。

Bootloader的设计
BootLoader就是在操作系统内核运行之前运行的一段小程序.通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终转到操作系统内核准备好合适的环境.这里设计的BootLoader主要有启动、下载和烧写引导uClinux的功能。BootLoader完成初始化工作后会通过串口在Windows的终端显示如下信息:0:tftpdownload1:WriteNorFlashwithdownloadfile2:Boot uClinux。

在终端的提示符“/"下输入0、1或2分别代表选择功能0、功能1或功能2。BootLoader执行对应的操作,功能0利用TFTP网络传输程序到SDRAM,默认下载地址为0x0c000800;功能1下载程序到flash,uClinux的映像文件image.rom的下载地址为0x00010000,Romfs.img的下载地址为0x00100000。这两个下载地址不是任意的,前一个地址与BootLoader的功能2有关;后一个地址与uClinux的文件系统定位有关。具体确定方法在下文论述;功能2启动烧写到Flash的uClinux。

因为本文的重点是uClinux的移植,所以这里不再详述BootLoader的具体实现过程,只介绍一下与uClinux相关的地方:(1)因为uClinux要利用S3C44B0的串口输出一些信息,所以BootLoader初始化过程中要设定处理器的主频,uClinux根据这个主频来设定串口寄存器,得到一定数值的波特率。本文选择的主频为61Mhz,波特率为115200。(2)执行功能2时,会调用一个MoveRun函数:

Void MoveRun(void)
{void (*fp)(U32,U32)=(void (*)(U32,U32))0xc300000;//0xc300000为uClinux的运行地址
NorFlashRead(0xc300000,0x10000,0x160000);//将烧写到0x10000处的image.rom移到0xc300000
(*fp)(0,0); //启动uClinux
}

(3)启动uClinux后,image.rom在0xc300000处自解压,并在0x0c000000处放置uClinux的中断向量表。即使uClinux内核已经得到处理器的控制权运行,一旦发生中断,处理器还是会自动跳转到从0x0地址开始的第一级中断向量表中的某个表项(依赖于中断类型)处读取指令运行。所以在编写BootLoader时,地址0x0处的一级异常中断矢量表只需简单地包含向0x0c000000处的中断向量表的跳转指令就可以,这样就能够正确地将发生的事件交给uClinux的中断处理程序来处理,BootLoader的第一级异常中断向量表如下所示:

bResetHandler; //跳转到初始化部分
ldrpc,=0x0c000004;//UndefinedInstructionHandler
ldrpc,=0x0c000008;//SoftwareInterruptHandler
ldrpc,=0x0c00000c;//PrefetchAbortHandler
ldrpc,=0x0c000010;//DataAbortHandler
b.
ldrpc,=0x0c000018;//IRQHandler
ldrpc,=0x0c00001c;//FIQHandler

uClinux内核的修改
目前uClinux已被成功移植到S3C44B0及其他多款ARM芯片上,但由于嵌入式操作系统的运行是与嵌入式系统的硬件密切相关的,而硬件的设计则会因为使用场合的不同而千差万别,因此,uClinux内核源代码中和硬件紧密相关的部分就应该针对特定的硬件作出适当的修改。

首先,从网站(www.uClinx.org)下载源码uClinuxdist-20040408,但这个发行包中的内核对S3C44B0X处理器的支持是不完整的,必须为内核打上补丁uClinux-2.4.24.patch(可以从http://www.hzlitai.com.cn下载),然后在终端下执行:patch-p0

(1)压缩内核代码起始地址修改
修改目录linux-2.4.x/arch/armnommu/boot/下的文件
Makefile里的如下代码:
ifeq(¥(CONFIG_BOARD_MBA44),y)
ZTEXTADDR=0x0c300000
ZRELADDR=0x0c008000
Endif

ZTEXTADDR代表映像文件image.rom自解压的起始地址,它的值是由BootLoader的功能2决定的。执行功能2,将image.rom从Flash转移到SDRAM的地址0x0c300000,内核自解压,所以ZTEXTADDR必须和这个值相同。ZRELADDR代表内核解压后代码输出起始地址。

(2)处理器配置选项的修改
修改目录linux-2.4.x/arch/armnommu/下的文件config. in里的如下代码:
define_intCONFIG_ARM_CLK64000000
if["¥CONFIG_SET_MEM_PARAM"="n"];then
define_hexDRAM_BASE 0x0C000000
define_hexDRAM_SIZE 0x00800000
define_hexFLASH_MEM_BASE 0x00000000
define_hexFLASH_SIZE 0x00200000
DRAM_BASE代表SDRAM的起始地址,
DRAM_SIZE代表SDRAM的大小,FLASH_MEM_BASE
代表Flash的起始地址,FLASH_SIZE代表Flash的大小。要根据自己的Flash和SDRAM来设定这些值

(3)内核起始地址的修改
修改目录linux-2.4.x/arch/armnommu/下的文件Makefile里的如下代码:
ifeq(¥(CONFIG_BOARD_MBA44),y)
TEXTADDR =0x0c008000
MACHINE =S3C44B0X
INCDIR =¥(MACHINE)
CORE_FILES: =¥(CORE_FILES)#romfs.o
Endif
TEXTADDR代表内核起始地址,与image.rom自解压后代码输出起始地址(ZRELADDR)相同。

(4)ROM文件系统的定位修改
修改目录linux-2.4.x/drivers/block下的文件blkmem.c里的如下代码:

#ifdefCONFIG_BOARD_MBA44
{0,0x00100000,-1},
#endif


0x00100000是文件系统的定位地址。本文中移植采用uClinux的文件系统ROMfilesystem,它的映象文件romfs.img要烧写到flash的某一地址。一旦该定位地址确定,在执行BootLoader的功能1时就要将romfs.img烧写到flash的这个地址。定位地址不是固定不变的,可以根据flash和image.rom的大小来更改。

(5)定义uClinux异常中断向量表的起始地址
修改目录linux-2.4.x/include/asm-armnommu/proc/下
的文件system.h里的如下代码:
#ifdefCONFIG_BOARD_MBA44
#undefvectors_base()
#definevectors_base() (0x0c000000)
#endif
vectors_base()定义了uClinux异常中断向量表的起始地址。uClinux启动后,一旦发生中断,处理器会自动跳转到从0x0地址开始的第一级中断向量表中的某个表项,再跳转到从vectors_base ()开始的uClinux异常中断向量表中的某个表项,执行中断服务程序。

(6)定义CPU体系结构和交叉编译器
修改目录linux-2.4.x/下的文件Makefile里的如下代码:
KERNELRELEASE=¥(VERSION).¥(PATCHLEVEL).
¥(SUBLEVEL)¥(EXTRAVERSION)
ARCH:=armnommu
HOSTCFLAGS=-Wall-Wstrict-prototypes-O2-fomit-frame-pointer
CROSS_COMPILE=arm-elf-ARCH:=armnommu定义了CPU的体系结构,S3C44B0采用的内核为无内存管理单元的ARM7TDMI,所以体系结构定义为armnommu。CROSS_COMPILE=arm-elf-定义了交叉编译器名称,这里采用的交叉编译器为 Arm-elf-tools-20030314.sh,所以名称定义为arm-elf-。

交叉编译环境的建立
由于Bootloader在物理上独立于uClinux,可以在集成开发环境下(如ADS)开发,但是uClinux必须在GNU环境下实现。Arm-elf-tools-20030314.sh是一个针对ARM的交叉编译器,在Linux操作系统下安装这个编译器,能够编译运行于ARM上的程序。在Linux环境下,从网站(如http://www.uClinux.org)下载Arm-elftools-20030314.sh。将其考到任何一个目录下,然后执行sh./arm-elf-tools-20030314.sh这样,交叉编译工具就安装好了。

uClinux内核的配置,编译及连接
在编译uClinux内核之前,首先要对内核进行配置。用makemenuconfig进行内核的配置,内核版本选linux-2.4.x,SystemType选S3C44B0ARM,库函数版本选u-Clibc。保存设置会出现内核配置窗口和用户程序配置窗口,内核配置中选择ROM文件系统支持和S3C44B0串口支持,用户配置按默认选项(可以根据自己的需要对内核和用户程序进行配置)。

配置完成后,开始编译内核,在终端分别执行makedep,makelib_only,makeuser_only,makeromfs,makeimage,make。当内核的编译工作完成后,在目录uClinux/images下会生成我们需要的映像文件image.rom,image.ram,romfs.img。

uClinux内核的下载与执行
使用fluted工具将Bootloader烧写到flash的0X000000处;利用Bootloader将内核映像image.rom下载到0x10000处;利用Bootloader将文件系统romfs.img下载到0x1000。00处.启动uClinux就可以在超级终端看到uClinux的欢迎信息和简单的shell提示符。

结束语

对于嵌入式系统开发人员来说,要将嵌入式操作系统应用到嵌入式系统中,首先要做的工作是根据不同的硬件平台移植操作系统,掌握移植的方法非常重要。本文所述的移植方法已经成功应用于多个项目的开发。所述的移植虽然是针对ARM处理器芯片S3C44B0,但重点阐述的是移植的思路和方法,对将uClinux移植到其他处理器为核心的硬件平台也有借鉴作用。

本文创新点:本文从如何将嵌入式操作系统uClinux与特定硬件相结合出发,分析移植uClinux到S3C44B0的过程。作者将自己成功移植所修改的部分作了详细的分析。有利于应用uClinux的人员快速理解,移植uClinux到特定的硬件平台。