跳至主要内容

【转】U-BOOT的启动流程及移植

1 Bootloaderu-boot简介

  Bootloader代码是芯片复位后进入操作系统之前执行的一段代码,主要用于完成由硬件启动到操作系统启动的过渡,从而为操作系统提供基本的运行环境,如初始化CPU、堆栈、存储器系统等。Bootloader 代码与CPU芯片的内核结构、具体型号、应用系统的配置及使用的操作系统等因素有关,其功能类似于PC机的BIOS程序。由于bootloaderCPU及电路板的配置情况有关,因此不可能有通用的bootloader,开发时需要用户根据具体情况进行移植。嵌入式Linux系统中常用的bootloaderarmbootredbootblobu-boot等,其中u-boot是当前比较流行、功能比较强大的bootloader,可以支持多种体系结构,但相对也比较复杂。bootloader的实现依赖于CPU的体系结构,大多数bootloader都分为stage 1stage 2两大部分。Bootloader的基本原理见参考文献。

  u-bootsourceforge网站上的一个开放源代码的项目。它可对PowerPC(MPC5xxMPC8xxMPC82xxMPC7xxMPC74xx) ARM(ARM7ARM9StrongARMXscale) MIPS(4kc5kc) X86等处理器提供支持,支持的嵌入式操作系统有LinuxVx-WorksNetBSDQNXRTEMSARTOSLynxOS等,主要用来开发嵌入式系统初始化代码bootloader。软件的主站点是http://sourceforge.net/projects/u-bootu-boot最初是由denx(www.denx.de) PPC-boot发展而来的,它对PowerPC系列处理器的支持最完善,对Linux操作系统的支持最好。源代码开放的u-boot软件项目经常更新,是学习硬件底层代码开发的很好样例。

  2 u-boot系统启动流程

  大多数bootloader都分为stage1stage2两大部分,u-boot也不例外。依赖于CPU体系结构的代码(如设备初始化代码等) 通常都放在stage1,且可以用汇编语言来实现,而stage2则通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。

  2.1 stage1 (start.s代码结构)

  u-bootstage1代码通常放在start.s文件中,它用汇编语言写成,其主要代码部分如下:

  (1) 定义入口由于一个可执行的Image必须有一个入口点,并且只能有一个全局入口,通常这个入口放在ROM(Flash) 0x0地址,因此,必须通知编译器以使其知道这个入口,该工作可通过修改连接器脚本来完成。
  (2) 设置异常向量(Exception Vector)
  (3) 设置CPU的速度、时钟频率及中断控制寄存器。
  (4) 初始化内存控制器
  (5) ROM中的程序复制到RAM中。
  (6) 初始化堆栈
  (7) 转到RAM中执行,该工作可使用指令ldr pc来完成。

  2.2 stage2 C语言代码部分

  lib_arm/board.c中的start_armbootC语言开始的函数,也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot) 的主函数,该函数主要完成如下操作:

  (1) 调用一系列的初始化函数。
  (2) 初始化Flash设备。
  (3) 初始化系统内存分配函数。
  (4) 如果目标系统拥有NAND设备,则初始化NAND设备。
  (5) 如果目标系统有显示设备,则初始化该类设备。
  (6) 初始化相关网络设备,填写IPMAC地址等。
  (7) 进入命令循环(即整个boot的工作循环) ,接受用户从串口输入的命令,然后进行相应的工作。

3 移植实例

  本系统开发板主要由S3C44B0X嵌入式微处理器、2MBFlash (SST39VF160) 8MBSDRAM(HY57V641620) 4LED以及ARM JTAG接口组成。该开发板上与S3C44B0X相关部分的功能框图如图1所示。

  3.1 u-boot文件下载

  u-boot文件的下载有两种方法,第一种是在Linux环境下通过CVS下载最新的文件,方法是:

$ cvs -d :pserver:anonymous@cvs.sourceforge.net:/cvsroot/u-boot login

  当要求输入匿名登录的密码时,可直接按回车键

$ cvs -z6 -d :pserver:anonymous@cvs.sourceforge.net:/cvsroot/u-boot co -P modulename

  第二种是通过ftp://ftp.denx.de/pub/u-boot/下载正式发布的压缩文件。

  3.2 u-boot文件的结构

  初次下载的文件有很多,解压后存放在u-boot文件目录下,具体内容已在readme文件中做了详细的介绍,其中与移植相关的主要文件夹有:

  (1) cpu/ 它的每个子文件夹里都有如下文件:

makefile
config.mk
cpu.c
和处理器相关的代码
interrupts.c
中断处理代码
serial.c
串口初始化代码
start.s
全局开始启动代码

  (2) board/ 它的每个子文件夹里都有如下文件:

makefile
config.mk
smdk2410.c
和板子相关的代码(smdk2410为例)
flash.c Flash
操作代码
memsetup.s
初始化SDRAM代码
u-boot.lds
对应的连接文件

  (3) lib_arm/ 体系结构下的相关实现代码,比如memcpy等的汇编语言的优化实现。

  3.3 交叉编译环境的建立

  要得到下载到目标板的u-boot二进制启动代码,还需要对下载的u-boot1.1.1进行编译。u-boot的编译一般在Linux系统下进行,可用arm-linux-gcc进行编译。一步一步建立交叉编译环境通常比较复杂,最简单的方法是使用别人编译好的交叉编译工具,方法如下:

  (1) http://handhelds.org/download/toolchain下载arm-linux-gcc-3.3.2.tar.bz2

  (2) 以用户名root登录,将arm-linux-gcc-3.3.2.tar.bz2 解压到 /root目录下

# tar jxvf arm-linux-gcc-3.3.2.tar.bz2

  (3) http://handhelds.org/download/toolchain下载arm-linux-toolchain-post-2.2.13.tar.gz,只是用了它的头文件而已,主要来自内核/linux-x.x/include

  (4) arm-linux-toolchain-post-2.2. 13.tar.gz 解压到/skiff/local/

# tar zxvf arm-linux-toolchain-post-2.2.13.tar.gz

 (5) 拷贝头文件到/root/usr/3.3.2/arm-linux/ 下,然后删除/skiff

# cp -dR /skiff/local/arm-linux/include /root/usr/3.3.2/arm-linux
# rm -fr /skiff

  这样就建立了armlinux 交叉编译环境。

  (6) 增加/root/usr/local/arm/3.3.2/bin到路径环境变量

# export PATH=$PATH:/root/usr/local/arm/3.3.2/bin

  可以检查路径变量是否设置正确。

# echo $PATH

  3.4 移植的预先编译

  移植u-boot到新的开发板上仅需要修改与硬件相关的部分即可。主要包括两个层面的移植,第一层是针对CPU的移植,第二层是针对board的移植。由于u-boot1.1.1里面已经包含S3C44B0的移植,所以笔者对板子myboard的移植主要是针对board的移植。移植之前需要仔细阅读u-boot目录下的README文件,其中对如何移植做了简要的介绍。为了减少移植的工作量,可以在include/config目录下选一个和要移植的硬件相似的开发板,笔者选的是b2开发板。具体步骤如下:

  (1) u-boot 1.1.1 下的cpu文件夹里已经包括了s3c44b0的目录,其下已经有start.sinterrupts.c以及cpu.cserial.c几个文件,因而不需要建立与cpu相关的目录。

  (2) board目录下创建myboard目录以及my-board.cflash.cmemsetup.su-boot.lds等文件。不需要从零开始创建,只需选择一个相似的目录直接复制过来,然后修改文件名及内容即可。笔者在移植u-boot过程中选择的是u-boot1.1.1/board/dave/B2目录。

  (3) include/configs目录下添加myboard.h,在这里可放入全局的宏定义等,也不需要从头创建,可以在include/configs目录下寻找相似的CPU的头文件进行复制,这里笔者用的是B2.h文件来进行相关的修改。

  (4) u-boot根目录下的Makefile文件进行修改,加入

myboard_config: unconfig
        @$(MKCONFIG) $(@:_config=) arm s3c44b0 myboard

  (5) 修改u-boot根目录下的Makefile文件,加入对板子的申明。然后在Makefile中加入myboard

LIST_ ARM7 = "B2  ep7312  impa7  myboard"

  (6) 运行make clobber,删除错误的depend文件。

  (7) 运行make myboard config

  (8) 执行到此处即表示整个软件的makefile已建立,这时可修改生成的makefile中的交叉编译选项,然后打开makefile 文件,并找到其中的语句:

ifeq($(ARCH) , arm) 
  CROSS_COMPILE=arm-linux-
end if

  接着将其改成

ifeq($(ARCH) ,arm) 
  CROSS COMPILE=/root/usr/local/3.3.2/bin/arm-linux-
end if

  这一步和上面的设置环境变量只要有一个就可以了。

  执行make,报告有一个错误,修改myboard/flash.c中的#include "../common/flash.c""u-boot/board/dave/common/flash.c",重新编译即可通过。

4 移植时的具体修改要点

  若预先编译没有错误就可以开始硬件相关代码的移植,首先必须要对移植的硬件有清楚地了解,如CPUCPU的控制寄存器及启动各阶段程序在Flash SDRAM中的布局等。

  笔者在移植过程中先修改/include/config/my-board.h头文件中的大部分参数(大部分的宏定义都在这里设置) ,然后按照u-boot的启动流程逐步修改。修改时应熟悉ARM汇编语言和C语言,同时也应对u-boot启动流程代码有深入的了解。B2板的CPU频率为75MHzFlash4MbitSDRAM16Mbit、串口波特率为115200bit/s、环境变量放在EEPROM中。根据两个开发板的不同,需要修改的有:CPU的频率、FlashSDRAM容量的大小、环境变量的位置等。由于参考板已经有了大部分的代码,因此只需要针对myboard进行相应的修改就可以了。与之相关的文件有/include/config/myboard.h(大部分的宏定义都在这里设置) /board/myboard/flash.c Flash的驱动序、/board/myboard/myboard.c(SDRAM的驱动程序) /cpu/s3c44b0/serial.c(串口的驱动使能部分) 等。

  /include/config/myboard.h是全局宏定义的地方,主要的修改有:

  将#define CONFIG_S3C44B0_CLOCK_SPEED 75改为

  #define CONFIG_S3C44B0_CLOCK_SPEED 64

  将 #define PHYS_SDRAM_1_SIZE 0x01000000 /* 16 MB */ 改为

  #define PHYS_SDRAM_1_SIZE 0x00800000 /* 8 MB */;

  将 #define PHYS_FLASH_SIZE 0x00400000 /* 4 MB*改为

  #define PHYS_FLASH_SIZE 0x00200000 /* 2 MB */;

  将 #define CFG_MAX_FLASH_SECT 256 /* max number of sectors on one chip */改为

  #define CFG_MAX_FLASH_SECT 35 ;

  将 #define CFG_ENV_IS_IN_EEPROM 1 /* use EEPROM for environment vars*/改为

  #defineCFG_ENV_IS_IN_FLASH 1

  其它(如堆栈的大小等) 可根据需要修改。

  由于FlashSDRAM的容量会发生变化,故应对启动阶段程序在FlashSDRAM中的位置重新作出安排。笔者将Flash中的u-boot代码放在0x0开始的地方,而将复制到SDRAM中的u-boot代码安排在0xc700000开始的地方。

  Flash的修改不仅和容量有关,还和具体型号有关,Flash存储器的烧写和擦除一般不具有通用性,应查看厂家的使用说明书,针对不同型号的存储器作出相应的修改。修改过程中,需要了解Flash擦写特定寄存器的写入地址、数据命令以及扇区的大小和位置,以便进行正确的设置。

  SDRAM要修改的地方主要是初始化内存控制器部分,由start.s文件中的 cpuinit crit完成CPU cache的设置,并由board/myboard/memsetup.s中的memsetup完成初始化SDRAMS3C44B0提供有SDRAM控制器,与一些CPU需要UPM表编程相比,它只需进行相关寄存器的设置修改即可,因而降低了开发的难度。

  串口波特率不需要修改(都是115200bit/s) ,直接用B2板的串口驱动即可。串口的设置主要包括初始化串口部分,值得注意的是:串口的波特率与时钟MCLK有很大关系,详见CPU用户手册。

  配置好以后,便可以重新编译u-boot代码。将得到的u-boot.bin通过JTAG口下载到目标板后,如果能从串口输出正确的启动信息,就表明移植基本成功。实际过程中会由于考虑不周而需要多次修改。移植成功后,也可以添加一些其它功能(LCD驱动等) ,在此基础上添加功能相对比较容易。

  5 结束语

  u-boot是一个功能强大的bootloader开发软件,适用的CPU平台及支持的嵌入式操作系统很多。本文是笔者在实际开发过程中根据相关资料进行摸索,并在成功移植了u-boot的基础上总结出来的。对于不同的CPU和开发板,其基本的方法和步骤是相同的,希望能对相关嵌入式系统的设计人员有所帮助。

 

评论

此博客中的热门博文

【转】AMBA、AHB、APB总线简介

AMBA 简介 随着深亚微米工艺技术日益成熟,集成电路芯片的规模越来越大。数字IC从基于时序驱动的设计方法,发展到基于IP复用的设计方法,并在SOC设计中得到了广泛应用。在基于IP复用的SoC设计中,片上总线设计是最关键的问题。为此,业界出现了很多片上总线标准。其中,由ARM公司推出的AMBA片上总线受到了广大IP开发商和SoC系统集成者的青睐,已成为一种流行的工业标准片上结构。AMBA规范主要包括了AHB(Advanced High performance Bus)系统总线和APB(Advanced Peripheral Bus)外围总线。   AMBA 片上总线        AMBA 2.0 规范包括四个部分:AHB、ASB、APB和Test Methodology。AHB的相互连接采用了传统的带有主模块和从模块的共享总线,接口与互连功能分离,这对芯片上模块之间的互连具有重要意义。AMBA已不仅是一种总线,更是一种带有接口模块的互连体系。下面将简要介绍比较重要的AHB和APB总线。 基于 AMBA 的片上系统        一个典型的基于AMBA总线的系统框图如图3所示。        大多数挂在总线上的模块(包括处理器)只是单一属性的功能模块:主模块或者从模块。主模块是向从模块发出读写操作的模块,如CPU,DSP等;从模块是接受命令并做出反应的模块,如片上的RAM,AHB/APB 桥等。另外,还有一些模块同时具有两种属性,例如直接存储器存取(DMA)在被编程时是从模块,但在系统读传输数据时必须是主模块。如果总线上存在多个主模块,就需要仲裁器来决定如何控制各种主模块对总线的访问。虽然仲裁规范是AMBA总线规范中的一部分,但具体使用的算法由RTL设计工程师决定,其中两个最常用的算法是固定优先级算法和循环制算法。AHB总线上最多可以有16个主模块和任意多个从模块,如果主模块数目大于16,则需再加一层结构(具体参阅ARM公司推出的Multi-layer AHB规范)。APB 桥既是APB总线上唯一的主模块,也是AHB系统总线上的从模块。其主要功能是锁存来自AHB系统总...

【转】select问题

问: 该串口初始化如下 ioctl(comm2Fd,FIOBAUDRATE,9600) ioctl(comm2Fd,FIOSETOPTIONS,OPT_RAW) 使用如下 FD_ZERO   (&readFds); FD_SET   (comm2Fd,   &readFds);   width   =   comm2Fd   +   1; FD_ISSET   (comm2Fd,   &readFds); FOREVER { if(timeoutvalue==0) { printf("\nselect   start!\n"); selectnum   =   select   (width,   &readFds,   NULL,   NULL,   NULL); printf("\nselect   over!\n"); }                                 ........... } 现在的状况是程序跑一段时间后会死机或这个串口通讯任务死掉,每次死机都是"select   start!"打印出来,而"select   over!"打印不出来,在仅这个串口通讯任务死掉的情况下,用comm1Fd超级终端登陆,查询任务状态,会发现tExcTask任务居然处于挂起状态??? 哪位大哥帮忙分析一下或给予一点提示,小弟不胜感激!! 答: sele...

搞笑

1.55岁的周润发宣布死后将捐出99%的财产,什么都不想带走。作家顾晓军评论道:千万不要捐到大陆来,不要害了无辜的官员。 2.发改委成立至今只做过两件事:1)涨价,2)替涨价辩护。 3.目前中国有效的反腐手段有:1夫妻反目;2家中被盗;3情人举报;4狗咬狗,5站错队 4.国外奶粉热销中国的原因:1没有三聚氰胺;2如果有,可以索赔巨款;3如果索赔不成,不会坐牢 5.1955年中国的人均收入是韩国的3.2倍,日本的1.1倍。但经过50多年翻天覆地的增长,2008年中国的人均收入是日本的3%,韩国7%,但韩国、日本从来没宣布自己经济怎么翻番,只有中国是天天说自己翻了很多番。 6.中国人固有一死,或死于地沟油,或死于石灰面粉,或死于结石奶粉,或死于毒疫苗,或死于危房,或死于拆迁,或死于躲猫猫,或死于日记,或死于酒色,或死于车轮下,或死于被自杀……死并不可怕,可怕的是你根本不知道自己是怎么死的! 7.中国不一定是和邻国土地争端最多的国家,但肯定是和本国公民土地争端最多的国家。 8.在谈所谓大国崛起之时,请扪心自问:你的收入崛起没有、你的住房面积崛起没有、你的护照免签国家数量崛起没有、你的食品安全崛起没有、你的医保社保崛起,你的国防力量增强了没有...如果都没有,那么大国再崛起关你P事。 9.日本人冈本真夜1997年的一首歌无耻地抄袭了我们2010年世博会的会歌,太可恶了!!? 10.什么是奇迹?我建了一座豆腐渣大楼,然后雇了150个短工装修,很多人说这房子容易塌,我充耳不闻。结果「哗啦」的塌了,把他们埋在废墟里整整八天八夜,我找人挖开塌坍时,有一百多人活着。这是个奇迹,更奇迹的是我他妈不但无罪,表彰会上我还成了救人的大英雄! 11.统计局宣布:中国城市人均月收入已突破9000人民币大关。拖祖国后腿的请自觉转发。 看到这个消息我不禁黯然神伤,仔细算算,我何止才拖了祖国的大腿,我都扒到祖国的臀部了,对不起,祖国---我是否扯到你的蛋了!!