蔡利平,任家富,童 锐,张敬伦
(成都理工大学 信息科学与技术学院,四川 成都610059)
嵌入式系统开发在当今日新月异的科技时代独树一帜,生活中大量的智能电子设备就是嵌入式应用的一个缩影,比如PDA、机顶盒和智能手机等。然而,在嵌入式软件的开发中,嵌入式引导程序 (Bootloader)的设计、开发与嵌入式系统的硬件息息相关,这个特性决定了不可能用一个通用程序作为众多嵌入式系统的引导程序。在这样的背景下,针对不同的开发环境设计不同的嵌入式系统引导程序成为首要问题,本文根据实际的情况,详细的分析了嵌入式引导程序的引导、启动原理,同时结合S3C2410开发板和 U-Boot-1.1.6引导程序,分析从 Nand Flash启动的具体流程,修改并完成了 U-Boot从Nand Flash启动的移植。
嵌入式软件从应用角度可以划分为4个层次:引导程序 (Bootloader)、内核、文件系统以及嵌入式应用软件(如GUI)。Bootloader是嵌入式系统中第一个被运行的程序,其功能是初始化部分硬件、为随后加载的系统内核准备相关的系统参数 (机器类型ID和启动参数标记列表在RAM中的地址)、加载内核到内存并将系统的控制权移交给内核。现在支持ARM体系结构的bootloader很多,比如Vivi、RedBoot、BLOB以及U-Boot等。不同的Bootloader在支持的体系结构和种类上有所不同,本文主要是针对U-Boot进行分析与移植。U-Boot是德国DENX研究中心开发设计的,其对现在市场上主流的操作系统、CPU都能提供良好的支持,功能相当的强大。U-Boot的文件组织方式与Linux内核相同,将功能或者特性相同的源文件放在一起,方便对源文件的管理与阅读。根据文件的不同作用,本人将U-Boot中所有的源文件相对的划分为下面的3个层次。如图1所示。
之所以这样分层,是因为:上层包含的/cpu和/board文件决定了系统所使用的ARM芯片类型以及与开发板相同或者相近的板级体系结构,如S3C2410开发板,相近的文件就 是/cpu/arm920t和/board/smdk2410,而/lib_xxx文件主要包含的是库文件,属于必不可少的部分;中间层文件include/configs/xxx.h中定义了众多的宏,其中定义的配置宏和参数宏在代码的编译过程中将决定哪些代码段将被包含,哪些代码段将不被包含,控制Bootloader所实现的功能,起一个承上启下的作用;底层主要包含了相关的驱动程序以及一些通用函数和接口函数。
在嵌入式系统中,根据引导系统存储的位置,引导系统启动主要分为有两种方式:Nor Flash引导和Nand Flash引导。这两种引导方式不管是从硬件连接还是从软件设计都有本质的不同,现在主流的引导程序基本上都支持从Nor Flash的启动引导,软件技术的实现相对比较成熟;但是对Nand Flash的启动支持还不是很完善,要能够从Nand Flash启动,需要引导程序和开发板都支持从Nand Flash启动。本文使用的U-Boot-1.1.6并不支持从Nand Flash启动的,而开发板S3C2410的硬件特性支持从Nand Flash启动。本文将通过分析U-Boot的启动流程,最终实现U-Boot从Nand Flash的启动与移植。
Bootloader的启动一般可以分为两个阶段。第一阶段主要是对部分硬件 (关闭看门狗、关中断、设置时钟和初始化存储设备等)的初始化、拷贝引导程序U-Boot自己全部的代码到SDRAM中以及为第二阶段的执行准备硬件环境 (清除BSS段、设置堆栈等),用汇编代码实现。第二阶段继续完成对外围硬件设备的检测与初始化,为内核引导提供硬件环境和引导参数。U-Boot在第二阶段对Nor Flash和对Nand Flash的支持是相同的,因此,支持Nand Flash启动的代码修改主要集中在U-Boot启动的第一阶段。为了得出U-Boot从Nor Flash引导与从Nand Flash引导的不同之处,这里结合韩国Mize公司的Vivi bootloader,Vivi最初主要是针对S3C2410X处理器的,支持从Nand Flash启动的引导,通过分析,第一阶段的引导流程如图2所示。
图2中方向①、②指明了Nand Flash与Nor Flash在引导程序第一阶段的不同之处,在程序中体现在/cpu/arm920t/start.S源文件的重定位代码段,源文件start.S也是U-Boot程序的入口文件,具体比较如图3所示。
U-Boot从Nor Flash启动的引导系统,只需要根据具体硬件的配置,更改少量的配置选项即可完成引导工作。通过上面的分析,为了实现Nand Flash引导启动需要修改U-Boot代码完成以下几个方面的问题:
(1)保证U-Boot的前4k代码不仅能够初始化相关的硬件,还要能够将存储在Nand Flash中的所有U-Boot代码拷贝到SDRAM中,这也是第一阶段的主要任务;
(2)在配置文件/include/configs/xxx.h中添加相关的宏,确定启动是从Nand Flash中进行,以及确定U-Boot代码在SDRAM中的起始位置、设置堆栈大小;
(3)最后需要实现对Nand Flash读写操作的命令支持,能够使U-Boot在控制终端使用Nand Flash命令对Nand Flash进行相关的操作。
图3 Nor Flash引导和Nand Flash引导的比较
系统引导启动方式 (Nor Flash or Nand Flash引导)是由引脚OM [1:0]来确定的,如果OM [1:0]为0x0,则是从Nand Flash引导;如果OM [1:0]的值为0x1,0x2则是从Nor Flash引导,这可以通过跳线来设置,有的开发板直接使用Nand Flash硬件连接。系统如果从Nand Flash启动,由于Nand Flash接口的特殊性,系统上电后会自动将Nand Flash前4k的代码复制到S3C2410内部集成的SRAM中,然后跳到这个SRAM缓冲区中0x0开始执行,这部分代码需要完成硬件的初始化并将U-Boot代码拷贝到SDRAM中后,然后跳转到SDRAM中执行。这里首先修改 源文件 uboot/board/s3c2410/start.S,在其中添加对Nand Flash的初始化代码,然后完成 U-Boot的拷贝:
coyp_myself_uboot:
(Nand Flash的初始化代码)
……
ldr r0,=UBOOT_RAM_BASE
//这是将U-Boot代码拷贝到SDRAM中的起始地址
mov r1,#0x0
//这是U-Boot在Nand Flash中的起始地址,即0x0
mov r2,#0x20000
//这是U-Boot代码的长度
bl nandTOsdram
//完成U-Boot到SDRAM拷贝的C函数
……
跳转到源文件nand_copy.c中的拷贝函数nandTOsdram中。这里的寄存器r0,r1,r2依次作为nandTOsdram的第一、第二和第三个参数。在/board/s3c2410/下添加文件nand_copy.c,主要代码如下:
……
int nandTOsdram (unsigned char*buf,unsigned long start_addr,int size){
int i,j;
if((start_addr & NAND_BLOCK_MASK)‖ (size&NAND_BLOCK_MASK)){
return-1; /*invalid alignment*/
}
/*chip Enable*/
NFCONF &= ~0x800;
for(i=0;i<10;i++);
for(i=start_addr;i< (start_addr+size);){
/*READ0*/
NFCMD=0;
/* Write Address*/
NFADDR =i &0xff;
NFADDR= (i>>9)&0xff;
NFADDR= (i>>17)&0xff;
NFADDR= (i>>25)&0xff;
wait_idle ();
for(j=0;j< NAND_SECTOR_SIZE;j++,i++){
*buf= (NFDATA &0xff);
buf++;
}
}
/*chip Disable*/
NFCONF|=0x800; /*chip disable*/
return 0;
}
通过在/cpu/arm920t/start.s中添加的Nand Flash初始化代码以及C源文件nand_copy.c解决了U-Boot从Nand Flash启动的第一个问题。
配置文件/include/configs/xxx.h控制整个开发板的编译选项,主要包括两类:以CONFIG_开头的文件用于选择CPU、SOC、开发板类型等,作为系统框架设计的一个选项;还有一类是以CFG_开头的宏,作为系统的参数出现,如设置缓冲池的大小、提示符等。为了获得U-Boot Nand Flash启动的支持,需要在配置文件中添加以下几个宏:
#define CONFIG_S3C2410_NAND_BOOT 1//控制编译从Nand Flash启动的代码
#define STACK_BASE 0x33f00000//定义堆栈在SDRAM中的位置以及长度
#define STACK_SIZE 0x8000
#define UBOOT_RAM_BASE 0x33f80000//U-Boot代码在SDRAM中的起始位置
#define NAND_CTL_BASE 0x4e000000//Nand Flash各个控制器的地址的定义
#define bINT_CTL (Nb) __REG (INT_CTL_BASE+ (Nb))
/
*offset*/
#define oNFCONF 0x00
#define oNFCMD 0x04
#define oNFADDR 0x08
#define oNFDATA 0x0c
#define oNFSTAT 0x10
#define oNFECC 0x14
经过上述两步的修改,U-Boot已经实现了从Nand Flash的启动,但是在控制终端并不能通过U-Boot的命令来对Nand Flash进行读写操作。
U-Boot对Nand Flash的读写操作命令并没有给予完整的支持。要先在配置文件中打开Nand Flash命令的控制宏:
#define CONFIG_COMMANDS\
(CONFIG_CMD_DFL | \
CFG_CMD_CACHE | \
CFG_CMD_NAND | 去掉之前的注释符号,使的CFG_CMD_NAND可用
/
*CFG_CMD_EEPROM|*/\
/*CFG_CMD_I2C |*/\
……)
同时,由于U-Boot默认的代码不能识别本文开发板上的Nand Flash K9F1208U0A芯片型号,还需要在文件/include/linux/mtd/nand_ids.h中的结构体添加如下代码,以识别芯片型号:
static struct nand_flash_dev nand_flash_ids[]= {
……
{"Samsung K9F1208U0A",NAND _MFR _SAMSUNG,0x76,26,0,3,0x4000,0},}
对 Nand Flash的读写操作在 U-Boot-1.1.6中有新旧两套代码,/driver/nand是新代码文件,/driver/nand_legacy是旧代码文件,如果在配置文件中定义了宏CFG_NAND_LEGACY,则通过旧代码部分获得对Nand Flash的支持,否则使用新代码支持Nand Flash的底层操作,本文使用的是新代码部分。在代码中还需要实现函数board_nand_init()的定义,实现对Nand Flash的底层操作,这个函数在文件/driver/nand/nand.c中只进行了声明:
……
extern void board_nand_init (struct nand_chip *nand);
……
没有定义的具体代码,添加源文件nflash.c并在此源文件中实现board_nand_init函数,函数的调用过程如图4所示。
图4 board_nand_init函数的调用过程
对Nand Flash底层函数的管理都是通过结构体struct nand_chip实现的,在board_nand_init函数中就是要实现这个结构体中各个底层函数,但是并不用实现结构体的每一个成员变量,这里必须要实现的结构体成员有:
读写信号nand->IO_ADDR_R= (void*)&s3c2410_mynand->NFDATA,nand->IO_ADDR_W= (void*)&s3c2410_mynand->NFDATA;控制信号函数nand->hwcontrol=s3c2410_nand_control_signal;芯片状态函数nand->dev_ready=s3c2410_nand_if_busy;片选信号函数 nand->select_chip=s3c2410_nand_select_chip以及位宽options的设置。到这里就完成了U-Boot从Nand Flash启动的代码修改,也实现了在终端对Nand Flash命令的支持。
在U-Boot的顶层目录执行命令:
make distclean
make s3c2410_config
make CROSS_COMPILE=arm-linux-
生成目标文件uboot.bin,将其通过并口烧写到Nand Flash中,然后重启,控制终端显示如下:
U-Boot 1.1.6(Nov 20 2010-15:32:38)
U-Boot code:33F80000->33F9A768BSS:->33F9EF18
DRAM: 64 MB
NAND: 64 MB
In: serial
Out: serial
Err: serial
CAI_s3c2410#
到这里就成功的完成了U-Boot的修改与移植。这里还有几个问题需要注意:为了能够在控制终端显示U-Boot在SDRAM中段的分布,需要将文件/lib_arm/board.c中的debug("U-Boot code:%08lX-> %08lX BSS:-> %08lX\n",_armboot_start,_bss_start,_bss_end)换成printf("U-Boot code:%08lX-> %08lX BSS:-> %08lX\n",_armboot_start,_bss_start,_bss_end);本开发板上没有nor flash,因此要在配置文件中注释掉flash的定义,并且注释掉/common/cmd_bootm.c中关于imls命令的程序段和/common/cmd_flash.c中的程序段。
结合硬、软件开发的嵌入式系统,分析、设计其启动流程是开发过程中第一个需要解决的问题。U-Boot引导程序以清晰明了的流程,详细的描述了怎么实现引导的具体过程。本文同时结合了Vivi的启动流程分析,实现了支持Nand Flash启动引导的U-Boot,详细的介绍怎么实现这个程序的修改过程。通过对U-Boot启动的分析能够深刻的理解到软件是怎么实现对硬件的操作,综合的应用了所学的知识,为开发嵌入式系统获得直接经验。
[1]DU Chunlei.The architecture of ARM and program [M].Beijing:Tsinghua University Press,2009:58-223 (in Chinese).[杜春雷.ARM体系结构与编程 [M].北京:清华大学出版社,2009:58-223.]
[2]LAI Yushu.ARM MPU and applications[M].Beijing:Publishing House of Electronics Industry,2007:75-150 (in Chinese).[赖于树.ARM微处理器与应用开发 [M].北京:电子工业出版社,2007:75-150.]
[3]WANG Minghu.The exploitation induction of ARM embedded Linux[M].Beijing:Publishing House of Electric Power China,2008:55-102 (in Chinese).[汪明虎.ARM嵌入式Linux应用开发入门 [M].北京:中国电力出版社,2008:55-102.]
[4]WEI Dongshan.The app exploitation entirety manual of embedded Linux[M].Beijing:The Press of People Postal and Electricity,2008:240-292(in Chinese).[韦东山.嵌入式Linux应用开发完全手册 [M].北京:人民邮电出版社,2008:240-292.]
[5]SUN Qiong.The application exploitation details of embedded Linux[M].Beijing:The Press of People Postal and Electricity,2006:116-121(in Chinese).[孙琼.嵌入式Linux应用程序开发详解[M].北京:人民邮电出版社,2006:116-121.]
[6]Stephen Prate.C primer plus [M].Beijing:Posts &Telecom Press,2010:354-376 (in Chinese).[Stephen Prate.C primer plus[M].北京:人民邮电出版社,2010:354-376.]
[7]DU Haixing.The analysis and transplant of embedded Bootloader based ARM [J].Microcomputer Information,2010,26 (10-2):58-59(in Chinese).[杜海星.基于ARM的嵌入式Bootloader分析与移植 [J].微计算机信息,2010,26 (10-2):58-59.]
[8]ZHAN Rongkai.The startup secret of embedded Bootloader[EB/OL].http://www.ibm.com/developerworks/cn/linux/l-btloader/,2010 (in Chinese).[詹荣开.嵌入式 Bootloader启 动 内 幕 [EB/OL].http://www.ibm.com/developerworks/cn/linux/l-btloader/,2010.]
[9]Tekkaman Ninja.Transplant U-Boot 1.2.0 to Weichuang 2410-S (S3C2410A) [EB/OL].http://blog.chinaunix.net/u1/34474/showart.php?id= 363269,2010 (in Chinese).[Tekkaman Ninja.移植 U-Boot.1.2.0到博创2410-S(S3C2410A) [EB/OL].http://blog.chinaunix.net/u1/34474/showart.php?id=363269,2010.]
[10]QIU Xuehong.The truth of microcomputer and interface technic[M].Xi’an:Xi’dian University Press,2007:66-134(in Chinese).[裘雪红.微型计算机原理及接口技术 [M].西安:西安电子科技大学出版社,2007:66-134.]
[11]ZHANG Shi.The tutorial of ARM embedded system [M].Beijing:China Machine Press,2008:35-66 (in Chinese).[张石.ARM嵌入式系统教科书 [M].北京:机械工业出版社,2008:35-66.]
[12]WU Shili.The resolve and practice of embedded Linux App exploitation [M].Beijing:China Machine Press,2008:135-146 (in Chinese).[吴士力.嵌入式LINUX应用开发全程解析与实战[M].北京:机械工业出版社,2008:135-146.]
[13]Qing Ting Dian Shui.The startup process of U-Boot[EB/OL].http://wenku.baidu.com/view/4428024ae45c3b3567ec8b4d.html,2010(in Chinese).[蜻蜓点水.U-Boot启动过程 [EB/OL].http://wenku.baidu.com/view/4428024ae45c3b3567ec8b 4d.html,2010.]
[14]CHU Shi Feng Mang.The manual of transplanting U-Boot to S3C2410 [EB/OL].http://wenku.baidu.com/view/1c2cb28da 0116c175f0e48f3.html,2010 (in Chinese).[初试锋芒.UBOOT移植S3C2440完全手册 [EB/OL].http://wenku.baidu.com/view/1c2cb28da0116c175f0e48f3.html,2010.]
[15]lien5.The Nand Flash drive analysis based on S3C2410 [EB/OL].http://hi.baidu.com/52hack/blog/item/675119df980b401b62279809.html,2010 (in Chinese).[lien5.对S3C2410平台上 Nand Flash的驱 动 分 析 [EB/OL].http://hi.baidu.com/52hack/blog/item/675119df980b401b62279809.html,2010.]