基于AT91RM9200的U-Boot启动分析和移植
发布时间:2024-11-12
发布时间:2024-11-12
本文采用U-Boot构建嵌入式系统的引导加载程序,在对U-Boot的启动工作机理进行了简略分析后,针对基于AT91RM9200的目标板对U-Boot作了具体的修改和移植。应用结果表明,移植后的U-Boot在目标板上运行良好,可成功引导Linux内核。
基于AT91RM9200的U-Boot启动分析和移植
周庆松,史小军
东南大学电子科学与工程学院,南京 (210096)
E-mail:摘 要:本文采用U-Boot构建嵌入式系统的引导加载程序,在对U-Boot的启动工作机理进
行了简略分析后,针对基于AT91RM9200的目标板对U-Boot作了具体的修改和移植。应用结
果表明,移植后的U-Boot在目标板上运行良好,可成功引导Linux内核。
关键词:U-Boot;移植;内核;AT91RM9200;嵌入式系统
1.引言
Bootloader代码是芯片复位后进入操作系统之前执行的一段代码,主要用于完成由硬件启
动到操作系统启动的过渡[1]。一般,Bootloader基于特定硬件平台实现,不但依赖于CPU的体
系结构,而且依赖于嵌入式系统板级设备的配置,因此需要修改源码来适合具体的嵌入式板
级设备。
本文基于AT91RM9200的嵌入式目标板和U-Boot源码资源,分析了U-Boot的启动过程,介
绍了U-Boot的移植方法和具体操作,最后讲述如何引导内核启动。
2.U-Boot简介
U-Boot,全称Universal Boot Loader,是遵循GPL条款的开放源码项目。他支持PowerPC、
ARM、X86、MIPS等体系结构的上百种开发板;并且支持多种嵌入式操作系统内核,如Linux、
NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS;具有较高的可靠性和稳定性,已经成为功
能最多、灵活性最强并且开发最积极的开放源码Bootloader。作为通用的BootLoader,U-Boot
可以方便的移植到其他硬件平台上[2]。
U-Boot移植一般都是针对嵌入式目标板的硬件资源,主要是CPU、FLASH 和SDRAM等情
况,以尽可能一致的原则,在U-Boot源码中,找到一个与目标板为同一个或同一系列处理器
的目标板模板,在此基础上再针对具体开发板对程序作相应的修改,比如不同型号存储芯片
的初始化等。这里笔者选用U-Boot 1.1.2版本,该版本支持基于at91rm9200的处理器配置,并
提供了一个目标板模板,即U-Boot源码下的board/at91rm9200dk模板。
3.U-Boot启动分析
在具体移植之前,先来了解一下U-Boot启动过程。U-Boot启动过程可以分成3个阶段[3]。
(1) 在Flash中运行汇编程序,进行基本硬件初始化,并将Flash中的启动代码复制到SDRAM中,
同时创造环境准备运行C程序;
汇编程序start.s是U-Boot启动后执行的第一个程序,它位于cpu/at91rm9200中,链接脚本
board/at91rm920dk/u-boot.lds决定U-Boot的入口函数位于该程序中。上电后,处理器首先执行
该程序,具体工作流程如图1所示。
(2) 跳转到SDRAM中执行,对硬件进行初始化,并向显示终端输出启动信息;
start_armboot是U-Boot执行的第一个C语言函数,它位于lib_arm/board.c中,主要完成
系统初始化工作,进入主循环,处理用户输入的命令。 具体工作流程如图2所示。
全局变量结构体gd主要用来保存开发板信息、终端存在标志位、环境变量结构体起始地
本文采用U-Boot构建嵌入式系统的引导加载程序,在对U-Boot的启动工作机理进行了简略分析后,针对基于AT91RM9200的目标板对U-Boot作了具体的修改和移植。应用结果表明,移植后的U-Boot在目标板上运行良好,可成功引导Linux内核。
址、环境变量校验标志位、frame buffer 基地址等。它是指向gd_t结构体的指针,gd_t结构体
定义在include\asm-asm\global_data.h中。
硬件初始化中执行函数及各函数作用如下所示:
board_init:基本的板级相关配置,主要包括:设置处理器类型和启动参数地址;
interrupt_init:中断处理初始化,主要对TC控制器作相应设置。
env_init:设置环境变量,初始化环境;
init_baudrate:指定串口的波特率;
serial_init:串口初始化设置;选择通讯端口,设置串口波特率和工作方式;
console_init_f:设置gd->have_console=1,表示可以使用串口通讯控制台;
display_banner:在控制台输出 U-Boot信息;
dram_init:设置SDRAM的起始地址和大小;
display_dram_config:在控制台输出 SDRAM信息;
flash_init:设置FLASH芯片ID号、每个扇区起始地址等信息,将信息送到相应的结构
体中;对FLASH中U-BOOT和环境变量存储扇区做软件写保护;
display_flash_config (size):在上位机终端输出FLASH大小。
图1 start.s函数执行流程 图2 start_armboot函数执行流程
(3) 将内核映像和根文件系统映像从flash拷贝到SDRAM中,为内核设置启动参数,进入内
核的入口函数。
U-Boot作为Bootloader,具备多种引导内核启动的方式。常用bootm命令引导内核映像
启动。使用bootm命令时,需要首先使用U-Boot自带的mkimage命令,将内核映像文件转换
成U-Boot格式映像。即在内核的前头加上64byte的信息帧头,供建立tag之用。
本文采用U-Boot构建嵌入式系统的引导加载程序,在对U-Boot的启动工作机理进行了简略分析后,针对基于AT91RM9200的目标板对U-Boot作了具体的修改和移植。应用结果表明,移植后的U-Boot在目标板上运行良好,可成功引导Linux内核。
bootm命令调用do_bootm函数。这个函数专门用来引导各种操作系统映像,可以支持引
导Linux、vxWorks、QNX等操作系统。具体完成的工作有:
① 保存内核引导地址;
② 分析内核帧头;
③ 复制内核映像到SDRAM中;
④ 调用do_bootm_linux()函数。
do_bootm_linux()函数是专门引导Linux映像的函数,它还可以处理ramdisk文件系统的映
像。具体完成的工作有:
① 检查是否有根文件系统映像文件。我们这里只用bootm命令引导内核映像;
② 将要传递给Linux的参数存放到标记列表中。内核将会从此处接收参数,完成参数传递;
③ 调用 Linux 内核。系统采用下列代码来进入内核函数:
theKernel = (void (*)(int, int))ntohl(hdr->ih_ep);
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
hdr是image_header_t类型的结构体,结构体定义位于include/image.h中;hdr->ih_ep指
向内核的第一条指令地址。第一行代码将theKernel函数指向内核首地址处;第二行代码调用
theKernel()函数,并通过r0、r1、r2将机器编号和参数链表物理地址传递给内核。
4.U-Boot修改与移植
4.1 嵌入式目标板介绍
本目标板以at91rm9200作为微处理器,板上存储系统包括NOR Flash、NAND Flash、
SDRAM等;外围支持设备有JTAG、串口、USB接口、 网络接口、SD Card 接口及显示接
口等。目标板硬件架构如图3所示;主要硬件资源如表1所示。
图3 嵌入式目标板硬件架构图
表1 嵌入式目标板主要硬件资源 硬件 型号 描述
8M Byte
32M Byte
64M Byte(2片)主频180MHz NOR Flash SST39VF6401BNAND Flash K9F5608U0D 网络芯片
本文采用U-Boot构建嵌入式系统的引导加载程序,在对U-Boot的启动工作机理进行了简略分析后,针对基于AT91RM9200的目标板对U-Boot作了具体的修改和移植。应用结果表明,移植后的U-Boot在目标板上运行良好,可成功引导Linux内核。
4.2 U-boot源码修改
根据目标板的配置,主要考虑修改以下U-Boot源码文件:
① include/configs/AT91RM9200dk.h。该头文件包含了SDRAM的一些设置和定义;
② board/AT91RM9200dk/flash.c。该程序完成的功能包括Flash初始化、打印Flash信息、Flah
擦除和Flash写入等操作。可在参考已有FLASH驱动的基础上,结合目标板FLASH数
据手册,进行适当修改;
③ include/flash.h。FLASH程序头文件,结合目标板修改FLASH型号和ID定义。
具体所作修改如下:
(1) include/configs/AT91RM9200dk.h中:
① 将 #undef CONFIG_BOOTBINFUNC 改为 #define CONFIG_BOOTBINFUNC
定义的目的是使能U-Boot中初始化SDRAM并拷贝自己到SDRAM中的相关代码。
② 修改SDRAM大小 #define PHYS_SDRAM_SIZE 0x4000000 /* 64 megs */
③ 修改FLASH大小和扇区数
#define PHYS_FLASH_SIZE 0x800000 /* 8 megs main flash */
#define CFG_MAX_FLASH_SECT 2048
④ 将 #define CFG_PROMPT "U-Boot> " 改为 #define CFG_PROMPT " zqs_1U-Boot> "
此处更改主要为了识别这是你修改后的U-Boot。
⑤ 添加 #define CFG_LONGHELP 1
该处定义的作用是在U-Boot下输入help命令时,可得到详细的命令解释。
(2) include/flash.h中:
① 添加 #define SST_ID_xF6401B 0x236D236D /* 39xF6401B ID (64M =
(3) board/AT91RM9200dk/flash.c中:
① 添加:OrgDef OrgSST39VF6401B[] = { {2048,4*1024},}; /* 2048 * 4 kBytes sectors */
② 屏蔽如下两行:
info->flash_id = ATM_MANUFACT & FLASH_VENDMASK;
printf ("Atmel: ");
在下面添加如下两行:
info->flash_id = SST_MANUFACT & FLASH_VENDMASK;
printf ("SST: ");
③ 在void flash_identification (flash_info_t * info)函数的最后添加:
else if ((device_code & FLASH_TYPEMASK) == (SST_ID_xF6401B &
FLASH_TYPEMASK)) {
info->flash_id |= SST_ID_xF6401B & FLASH_TYPEMASK; printf ("SST39VF6401B (64Mbit)\n");}
④ 在ulong flash_init (void)函数中添加:
else if ((flash_info[i].flash_id & FLASH_TYPEMASK) ==
(SST_ID_xF6401B & FLASH_TYPEMASK)) { /* SST39VF6401B Flash */
pOrgDef = OrgSST39VF6401B;
flash_nb_blocks = sizeof (OrgSST39VF6401B) / sizeof (OrgDef); }
⑤ 在 void flash_print_info (flash_info_t * info)函数中添加:
case (SST_MANUFACT & FLASH_VENDMASK):
printf ("SST: ");
break;
4M x 16 )*/
本文采用U-Boot构建嵌入式系统的引导加载程序,在对U-Boot的启动工作机理进行了简略分析后,针对基于AT91RM9200的目标板对U-Boot作了具体的修改和移植。应用结果表明,移植后的U-Boot在目标板上运行良好,可成功引导Linux内核。
⑥在 void flash_print_info (flash_info_t * info)函数中添加:
case (SST_ID_xF6401B & FLASH_TYPEMASK):
printf ("SST39VF6401B (64Mbit)\n");
break;
⑦ 在int flash_erase (flash_info_t * info, int s_first, int s_last)函数中,将以下几句用/* */屏蔽掉:
if ((info->flash_id & FLASH_VENDMASK) !=
(ATM_MANUFACT & FLASH_VENDMASK)) {
return ERR_UNKNOWN_FLASH_VENDOR;
}
并在下面添加如下几行:
if ((info->flash_id & FLASH_VENDMASK) !=
(STT_MANUFACT & FLASH_VENDMASK)) {
return ERR_UNKNOWN_FLASH_VENDOR;
}
至此,UBOOT源码文件修改完毕。
4.3 U-Boot编译与测试
U-Boot的源码通过GCC和Makefile组织编译。顶层目录下的Makefile设置开发板的定
义,递归地调用各级子目录下的Makefile,把编译过的程序链接成U-BOOT映像[2]。
这里上位机操作系统采用Redhat9.0,交叉工具链采用cross-2.95.3。GCC安装的路径为
/usr/loacal/arm/2.95.3,在环境变量PATH中添加相应路径,就可以直接使用arm-linux-gcc命令。
编译U-BOOT分两步,第一步配置,执行命令: make at91rm9200dk_config
第二步编译,执行命令: make
编译完成,生成3个映像文件system.map、u-boot、u-boot.bin,和1个符号表system.map,
一般u-boot.bin最为常用,直接按照二进制格式下载。
使用FLASH烧写程序将u-boot.bin烧进NOR FLASH中,目标板重新上电复位后,U-Boot
启动成功,在超级终端里会显示如下信息:
出现Warning的原因是还未设置环境变量。设置环境变量后执行saveenv命令即可去掉
Warning.
5.引导内核
U-Boot的最终目的是引导内核启动。上述仅仅启动了U-Boot,要引导内核启动还需要设
置环境变量、下载内核和根文件系统映像、执行引导内核启动命令。假设内核映像文件为
zImage,根文件系统映像文件为myramdisk.gz(生成方法略)。具体方法如下:
(1) 启动目标机,在U-BOOT中进行网络参数等环境变量设置
U-Boot> setenv ethaddr 12:34:56:78:90:aa
本文采用U-Boot构建嵌入式系统的引导加载程序,在对U-Boot的启动工作机理进行了简略分析后,针对基于AT91RM9200的目标板对U-Boot作了具体的修改和移植。应用结果表明,移植后的U-Boot在目标板上运行良好,可成功引导Linux内核。
U-Boot> setenv ipaddr 192.168.0.11
U-Boot> setenv serverip 192.168.250
U-Boot> setenv netmask 255.255.255.0
U-Boot> setenv bootargs root=/dev/ram rw initrd=0x21200000,6000000
ramdisk_size=15360 console=ttyS0,115200 mem=64M
U-Boot> setenv bootcmd cp.b 10300000 21200000 300000\; bootm 10100000 U-Boot> saveenv
这里网络环境变量设置的目的是为了能够使用TFTP协议;bootargs用来定义传递给Linux
内核的命令行参数;Bootcmd定义自动启动时执行的命令;bootm 10100000表示从10100000
处引导内核程序。
(2) 给内核映像加帧头[4]
在上位机LINUX环境下,将U-Boot\tools\mkimage.exe COPY 到 \bin目录下;输入如下命令:
[root@localhost tftpboot]#mkimage -n 'linux-2.6.19' -A arm -O linux -T kernel -C none -a
0x20008000 -e 0x20008000 -d zImage zImage.img
这里zImage为原始内核映像文件名;zImage.img为生成的加过帧头的内核映像名。
(3) 加载内核和根文件系统映像到Flash中
加载zImage.img到0x10100000,加载myramdisk.gz到0x10300000。
至此,我们将UBOOT 、内核、根文件系统都下载到Flash中了,并且设置了环境变量。
重启目标板,等待延时时间结束自动进入本地装载模式,即可引导内核启动。
上面讲的是将内核和根文件系统固化到Flash中的情况,即使用本地加载模式,当以嵌入
式产品发布的时候,BootLoader必须工作在这种模式下。但我们实际在初期调试的时候,可
以在下载操作模式下直接用TFTP命令将这些映像文件下载到SDRAM中,然后用bootm命令
从SDRAM中引导。此时在给内核映像加帧头的时候要注意,bootm xxxx 指定的地址xxxx是
否与mkImage命令处的 -a指定的加载地址相同。如果不同,mkImage命令的写法和上面介绍
的一致。如果相同,在使用mkImage命令时,-e参数后的入口地址要比-a参数后的存储地址
推后64byte。
6.结论
U-Boot是一个功能强大的Bootloader开源软件,它支持上百种开发板和多种嵌人式操作系
统,可方便地移植到各种硬件平台上。目前,笔者移植的U-Boot已成功运行在目标板上,并
在此基础上成功地加载了Linux内核和根文件系统,为后续的驱动和应用开发奠定了基础。对
于不同的CPU和开发板,U-Boot的启动原理和移植步骤大致相同。希望本文能对学习U-Boot
的朋友有所帮助。
参考文献
[1]
[2]
[3]
[4]
张进,姜威.U-Boot的启动流程及移植[J],国外电子元器件,2005,5,11~14。 孙纪坤,张小泉.《嵌入式Linux系统开发技术详解-基于ARM》[M],北京:人民邮电出版社,2006.8。 焦玉全,黄乡生,鲍玉军.U-Boot在S3C2410上的移植[J],电子设计应用,2006,3,126~128。 Karim Yagbmour.《构建嵌入式LINUX系统》[M],北京:中国电力出版社,2004.12。
本文采用U-Boot构建嵌入式系统的引导加载程序,在对U-Boot的启动工作机理进行了简略分析后,针对基于AT91RM9200的目标板对U-Boot作了具体的修改和移植。应用结果表明,移植后的U-Boot在目标板上运行良好,可成功引导Linux内核。
Start analysis and porting of U-Boot based on AT91RM9200
board
Zhou Qingsong,Shi Xiaojun
Dept. of Electronic Science and Engineering,Southeast University,Nanjing (210096)
Abstract
This paper develops a bootloader for embedded system with the U-Boot. After analyzing the booting mechanism of U-Boot, the modification and porting in an embedded system board based on
AT91RM9200 are done in detail. The application shows that U-Boot runs well and can lead Linux kernel successfully.
Keywords:U-Boot,porting,kernel,AT91RM9200,embedded system
作者简介:
周庆松,1980,男,硕士研究生;
史小军,1952,男,教授,硕士生导师。