要:分析ARM处理器引导装载程序的特点以及在此类平台上实现bootloader的途径。探讨利用GNU工具开发bootloader程序的方法和开发特点,并且结合项目中在该系统上移植bootloader的成功经验,阐述U-boot在ARM平台上的移植步骤和关键。对嵌入式开发人员有一定的借鉴意义。
关键词:bootloader U-boot 嵌入式系统 AT91RM9200
基于ARM920T核的AT91RM9200芯片以其丰富的内部外设,高达200MIPS的处理速度,以及它温度范围宽的特点,在工业控制领域嵌入式开发中大有应用的空间。Bootloader是用来引导操作系统的引导装载程序,用来初始化硬件设备、确立内存空间的映射,为最终引导操作系统内核提供一个合适的软硬件环境。它严重地依赖硬件环境,往往因使用的芯片、外部设备、操作系统的内核配置而不同,它的实现是嵌入式开发中必不可少的环节。
实现适合本系统的引导程序方法有两种:一是自行开发的bootloader,其特点是可以使这个程序在满足要求的基础上占用尽量的小的空间,但是工作量较大,开发周期延长,除了一些特殊要求的情况,工程开发中一般不会自行编写;二是使用已有的代码进行移植,特点是工作量小,有vivi、U-boot、Blob等很多开源的bootloader可用,这些程序支持的PowerPC,ARM,MIPS等多种平台,开发者只需做相对较少的移植工作就可以,出于工程开发角度,往往采取这种方式。
笔者开发了基于AT91RM9200的雷达监控分机测试板,本文将以此嵌入式板为例,介绍用GNU工具开发ARM程序的方法,探讨如何利用这种方法编写自己的bootloader,并详细地介绍了U-boot的移植步骤和要点。
1硬件特点
1.1AT91RM9200处理器启动特点
AT91系列处理器有片内和片外两种启动模式[1],支持地址的重映射,在ARM芯片中具有代表性。
AT91RM9200内部集成有16K字节的SRAM和128K字节的ROM。若是BMS引脚为低电平则从NCS0所接的外部的Flash芯片启动。若BMS引脚为高电平则从内部ROM启动,ROM中固化了FirmWare,这段固化的程序先后自动检测SPI连接的DataFlash,TWI连接的EEPROM的,EBI连接的8位的并行Flash芯片是否有合法的程序,如果有则放入SRAM中执行,如果没有检测到,便初始化调试串口和USB的设备端口,分别支持Xmodem和DFU协议的文件下载,可以将用户传送的文件放入内部SRAM中[2]。
由于本芯片支持地址Remap(地址重映射),在下载完后将SRAM的地址由0x0020_0000重新映射到0x0000_0000,将内部ROM地址由0x0000_0000映射到0x0010_0000,然后从地址0x0000_0000的内部SRAM开始执行。
1.2 Bootloader的下载和烧写
很多ARM芯片同AT91系列芯片一样,支持Remap,这就为使用串口下载程序和对Flash的烧写提供了方便。这种芯片在使用bootloader之前一般需要两个前期的引导程序。本系统中使用了loader.bin和boot.bin两个程序:其中loader.bin运行于内部RAM,用来向SDRAM下载程序并运行;boot.bin固化在flash的起始地址下(如图1所示)用来解压引导Flash中的U-boot程序。
设置跳线,使系统上电后从内部启动,通过串口下载loader.bin程序,该程序的大小一定要小于16K字节,即内部SRAM的容量。如上文所述,下载后会运行它,由这个程序负责通过Xmodem协议将u-boot.bin程序下载到SDRAM中并运行,开发者再通过U-boot的cp命令将boot.bin和u-boot.bin的压缩文件u-boot.gz烧写入Flash,下次从外部启动时就可以直接启动U-boot了。其中boot.bin,实现将u-boot.gz的解压装入SDRAM并且执行。
ATMEL公司提供了针对他们出的该款芯片开发板的boot和loader的代码,可以从网上下载到,开发者可以对比一下参数设置,如果必要的话要对一些参数进行修改。
下面是这两个程序中比较关键的参数。loader当中的关键参数是AT91C_UBOOT_BASE_ADDRESS,用Xmodem协议接收的文件将存放在这个地址下。它的宏定义在main.h中:
#define AT91C_UBOOT_BASE_ADDRESS 0x21F00000 。
Boot中的关键的参数是:
#define SRC 0x10010000
/*在flash中的u-boot.gz的地址*/
#define DST 0x21F00000
/*uboot.gz解压后要copy到SDRAM中的地址*/
#define LEN 0x020000
/*解压后的大小(字节)*/
这些参数根据具体情况可能需要修改,特别是SRC要和U-boot中的相关设置一致,具体参数将在3中介绍。图1是Flash存储器的空间分配情况,分别列出了各个地址段的用途。
图1 Flash芯片的存储分配情况
1.3 本嵌入式板的存储空间情况
笔者开发的ARM板的与bootloader相关的关键存储空间分布情况如下:
32M字节SDRAM: 0x2000_0000 – 0x21FF_FFFF
2M 字节 Flash: 0x1000_0000 – 0x101F_FFFF
2 用GNU工具开发bootloader
GNU提供了免费的编译工具,可从网上下载。针对ARM平台的交叉编译工具有汇编器arm-linux-as, C编译器arm-linux-gcc,连接器arm-linux-ld,以及二进制转换工具arm-linux-objcopy。 GNU的编译器功能非常强大,共有上百个操作选项,满足开发者的各种需要。它的特点是开发成本低,无需昂贵的仿真器,不但可以开发操作系统下运行的程序,也可以开发裸机应用程序[3]。GNU工具都运行在Linux下,开发者需要1台运行Linux的PC作为宿主机,开发后下载到板子上。U-boot,vivi等都利用了这些工具。为开发者的开发提供了很好的范例。一般地,基于GNU工具的程序开发流程如下:(1)编写C、C++或者汇编源程序;(2)用相关编译器生成目标文件;(3)编写连接脚本;(4)用连接器生成最终文件(elf格式);(5)用二进制转换工具生成可下载的二进制代码。
编写适用于本系统的Bootloader以完成最基本的引导操作系统的功能为目的。作为引导程序的基本功能应该包括:(1)对硬件的初始化,如设置异常向量,设置CPU的速度、时钟频率和中断控制寄存器,初始化内存控制器,初始化堆栈等;(2)支持文件的下载,串口的Kermit协议下载或者支持tftp协议的网口下载,后者实现相对复杂,但是速度快,可以根据情况选择;(3)对Flash的操作;(4)最好支持下载和自举两种工作模式;(5)解压内核,配置参数等。其中功能(1)直接涉及硬件,实现时应该使用GNU汇编。不同于ADS环境下的ARM汇编程序编写,这种汇编语言有其特点,支持预处理,可以使用#include<>和C语言风格的注释,文件的扩展名是大写的S(编译器以此区分是否预处理汇编程序),开发者可以参考GNU提供的资料,以及U-boot的源代码。
3 U-boot的移植
3.1 源代码分析
U-BOOT(Universe Bootloader),是Sourceforge网站的开放源代码项目,支持PowerPC、ARM、MIPS和x86等多种体系结构,代码便于移植[4]。本人开发中采用了U-Boot1.1.2的源代码,GCC编译器版本是2.95.3。开发者首先要了解代码的结构和功能。在此基础上分析代码的运行顺序和相互调用关系。

图2 U-boot的执行顺序
U-Boot的运行过程如图2所示,程序从cpu/at91rm9200/start.S开始,start.S中用.globl _start定义了入口,之后设置了处理器的状态,初始化了中断和内存时序并且确定是否需要对整个U-Boot代码重定位,跳转到star_armboot()运行,这个函数在/lib_asm/board.c中定义,完成了一些初始化工作,之后便循环调用commmon/main.c中的main_loop()函数。开发时可以按这个次序阅读代码。在代码的board目录下,可以找到与自己的芯片相同的开发板对应目录,此处选择的是目录at91rm9200dk,移植时修改工作也多在此处。
3.2 移植要点
进行移植主要关注并进行修改的代码文件有和相应的修改要点如下:
(1) include/commom.h。代码中用很多的条件编译包含了一些头文件,并且声明了一系列的基本函数,这个头文件被很多文件包含。了解这个文件的内容对理解、修改代码很有帮助。
(2) include/configs/at91rm9200dk.h。这个文件中是针对本电路板的详细设置信息,关键的设置有时钟设置,终端选择(GDBU、USART0、USART1),SDRAM的起始地址PHYS_SDRAM和大小PHYS_SDRAM_SIZE,Flash存储器的起始地址 PHYS_FLASH_1和大小PHYS_FLASH_SIZE,以及Flash中U-Boot的环境变量的存储地址CFG_ENV_ADDR和大小CFG_ENV_SIZE,以及U-Boot的起始地址CFG_U_BOOT_BASE和大小CFG_U_BOOT_SIZE。其他的参数可以根据开发者的需要进行修改。以上的参数要根据实际情况修改。
根据开发经验,容易忽略的是FLASH中环境变量的存储地址CFG_ENV_ADDR和大小CFG_ENV_SIZE的设置。U-boot中的saveenv命令执行时会将setenv命令设置的环境变量存储在Flash,要求起始地址是Flash的一个段(section)的边界,项目中根据AM29LV160DB芯片的手册以及电路原理图上Flash的地址线的连接对本文件做以下修改:
#define CFG_ENV_ADDR (PHYS_FLASH_1 + 0xe000)
#define CFG_ENV_SIZE 0x2000 /* 0x8000 */
修改为:
#define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x8000)
#define CFG_ENV_SIZE 0x8000 /*0x8000 */
Flash存储器的地址分配情况可以参见图1。
(3) board/at91rm9200dk/config.mk。这里面将TEXT_BASE设置为0x21f00000,与本文第1部分中提到的Boot程序的DST参数设置一致。
(4) board/at91rm9200dk/flash.c。由于Flash芯片选用的与源代码所针对的Flash芯片不同,首先要在include/flash.h中加入下面的宏:#define AMD_ID_LV160DB 0x22492249,这是AM29LV160DB芯片的设备ID号,为了在flash_identification()函数中正确地识别。另外在本文件中还要加入定义
OrgDef OrgAMDLV160DB[] ={
{ 1, 16*1024 },
/* 1 * 16 kBytes sectors */
{ 2, 8*1024 },
/* 2 * 8 kBytes sectors */
{ 1, 32*1024 },
/* 1 * 32 kBytes sectors */
{ 31, 64*1024 },
/* 31 * 64 kBytes sectors */
};
这个OrgDef数组给出了Flash中的段的信息。在函数flash_identification(flash_info_t * info)中修改打印的信息,flash_init(void)和 flash_print_info(flash_info_t * info)中的变量要相应的修改,最后 flash_erase()中的身份判断部分相应的修改(如果只支持一种Flash芯片的话可以去掉)。
按照本系统硬件情况,关键是Flash的驱动部分的修改。由于Bootloader是为了引导操作系统,如本文的第2部分分析完成最基本的硬件的初始化即可,所以在实际移植中经常需要做的一般如上文所述。
接下来在Linux下进行编译,设置环境变量PATH为交叉编译器的路径所在目录,如:
PATH=$PATH:/usr/local/arm/2.95/bin
在代码的顶层目录下执行以下命令:
make distclean
make at91rm9200dk_config
make
编译成功可以得到得到三个文件:u-boot,u-boot.bin,u-boot.srec。其中boot包含有很多调试信息,可以被很多调试程序读,开发者也可以用readelf、objdump等命令来查看里面包含的段地址等信息。u-boot.bin文件是ARM可以直接执行的二进制的文件。u-boot.srec是 MotololarMT srec格式的文件。
按照1.2中介绍的方法烧写U-boot到Flash芯片,设置跳线,使BMS引脚为低电平,CPU从外部启动,从超级终端显示U-boot的启动信息。
3.3 调试
调试过程中遇到的问题可能是移植的问题,也有可能是硬件的问题,需要开发者做出判断。仔细的阅读U-boot的源代码,对于了解硬件环境,进行调试有很大好处。同时代码有一些用于调试的条件编译,用dbg ()、debug()等函数输出调试信息,开发者可以通过这些调试信息输出函数得到编译以得到相关部分的调试信息。
编译通过之后将u-boot.bin载入SDRAM中运行,分别试验erase,cp,printenv,saveenv等命令检测对Flash的操作,使用tftp命令以检测网口下载功能,然后装载操作系统内核,完成以上的任务则移植成功。经过以上步骤移植的U-Boot已经在本人开发的ARM板上顺利的引导Linux操作系统。
4 总结
本文是笔者结合AT91RM9200的开发经验,首先介绍了该处理器的特点,探讨了利用GNU开发bootloader的一般方法和步骤,最后详细地分析了U-boot在嵌入式系统上的移植。基于其他的CPU的嵌入式平台上的Bootloader的移植与此相似,希望本文能对嵌入式开发人员有借鉴意义。AT91RM9200是适合于工业控制、汽车电子、医疗器械等领域的一款基于ARM920T核的高性能芯片,属于当前比较高端的RISC处理器。文章首先分析了AT91RM9200芯片引导的特点,然后在基于AT91RM9200的嵌入式系统上实现Bootloader(操作系统的引导装载程序)的方法,特别是通过对移植U-boot的方法和常见问题的详细介绍。
本文作者创新点:阐明了在基于RISC芯片(ARM、MIPS,PPC等)的系统开发中实现bootloader的方法,为广大的嵌入式开发人员提供了一个参考。
参考文献:
[1] 朱义君 杨育红 赵凯 段志英,AT91系列ARM微控制器体系结构与开发实例[M],北京航空航天大学出版社,2005
[2] Atmel Corporation, ARM920TTM Based Microcontroller AT91RM9200,2004
[3] Wookey, Chris Rutter, Jeff Sutherl, Paul Webb, The GNU Toolchain for ARM Targets HOWTO.
[4] The DENX U-BOOT and Linux Guide (DULG), http://www.denx.de/twiki/bim/view/DULG/Mannual
[5] 万永波 张根宝 田泽 杨峰,基于ARM的嵌入式系统Bootloader启动流程分析, 微计算机信息, 2005年,第21卷11-2期,90页
|