[转]u-boot移植资料整理

来源:互联网 发布:查淘宝信誉的网址 编辑:程序博客网 时间:2024/05/03 04:29

原文地址 : http://blog.sina.com.cn/s/blog_68f2b9e20100iyx3.html

//////////////////////////////////////////////////////////////////////////////////////////////
首先,了解一下bootloader。bootloader是系统加电后运行的第一段代码。它要完成的工作就是初始化硬件设备,建立内存空间的映射图,这样为最终调用操作系统内核做好准备。
 
bootloader的操作模式
(1)启动加载模式(bootloading)
(2)下载模式(downloading)
开发时要用(2),targetboard上的bootloader将通过串口或者网络等通信手段从host上下载内核映象和根文件系统映象等到ram中。
 
bootloader的启动方式:网络启动、磁盘启动、flash启动。
 
bootloader的种类
区分一下“bootloader”和“monitor”的概念。bootloader只是引导设备并且执行主程序的固件;而monitor还提供了更多的命令行接口,可以进行调试、读写内存、烧写flash、配置环境变量等。monitor在嵌入式系统开发过程中还可以提供很好的调试功能,开发完成后,就完全配置成了一个bootloader。所以,习惯上把它们统称为bootloader。我现在要使用的u-boot就是典型的monitor。
 
bootloader的启动流程
搜集了一些资料,写的比较精彩,放在这里。。。
 
 
资料一:
系统上电,检测BMS,选择系统的启动方式,如果BMS为高电平,则系统从片内ROM启动。AT91RM9200的ROM上电后被映射到了0x0和0x100000处,在这两个地址处都可以访问到ROM。由于9200的ROM中固化了一个BOOTLOAER程序。所以PC从0X0处开始执行这个BOOTLOAER(准确的说应该是一级BOOTLOADER)。这个BOOTLOER依次完成以下步骤:

1.              PLLSETUP:设置 PLLB产生48M时钟频率提供给USB DEVICE。同时DEBUG USART也被初始化为48M的时钟频率。
2.              相应模式下的堆栈设置
3.              检测主时钟源(Mainoscillator)
4.              中断控制器(AIC)的设置
5.              C变量的初始化
6.              跳到主函数

完成以上步骤后,我们可以认为BOOT过程结束,接下来的就是LOADER的过程,或者也可以认为是装载二级BOOTLOER。
AT91RM9200按照DATAFLASH、EEPROM、连接在外部总线上的8位并行FLASH的顺序依次来找合法的BOOT程序。所谓合法的指的是在这些存储设备的开始地址处连续的存放的32个字节,也就是8条指令必须是跳转指令或者装载PC的指令,其实这样规定就是把这8条指令当作是异常向量表来处理。必须注意的是第6条指令要包含将要装载的映像的大小。关于如何计算和写这条指令可以参考用户手册。一旦合法的映像找到之后,则BOOT程序会把找到的映像搬到SRAM中去,所以映像的大小是非常有限的,不能超过16K的大小。当BOOT程序完成了把合法的映像搬到SRAM的任务以后,接下来就进行存储器的REMAP,经过REMAP之后,SRAM从映设前的0X200000地址处被映设到了0X0地址并且程序从0X0处开始执行。而ROM这时只能在0X100000这个地址处看到了。至此9200就算完成了一种形式的启动过程。如果BOOT程序在以上所列的几种存储设备中找到合法的映像,则自动初始化DEBUG USART口和USBDEVICE口以准备从外部载入映像。对DEBUG口的初始化包括设置参数115200 8 N 1以及运行XMODEM协议。对USBDEVICE进行初始化以及运行DFU协议。现在用户可以从外部(假定为PC平台)载入你的映像了。在PC平台下,以WIN2000为例,你可以用超级终端来完成这个功能,但是还是要注意你的映像的大小不能超过13K。一旦正确从外部装载了映像,接下来的过程就是和前面一样重映设然后执行映像了。我们上面讲了BMS为高电平,AT91RM9200选择从片内的ROM启动的一个过程。如果BMS为低电平,则AT91RM9200会从片外的FLASH启动,这时片外的FLASH的起始地址就是0X0了,接下来的过程和片内启动的过程是一样的,只不过这时就需要自己写启动代码了,至于怎么写,大致的内容和ROM的BOOT差不多,不同的硬件设计可能有不一样的地方,但基本的都是一样的。由于片外FLASH可以设计的大,所以这里编写的BOOTLOADER可以一步到位,也就是说不用像片内启动可能需要BOOT好几级了,目前AT91RM9200上使用较多的bootloer是u-boot,这是一个开放源代码的软件,用户可以自由下载并根据自己的应用配置。
 
 
资料2
loader.bin, boot.bin,u-boot.bin代码执行流分析.

以上三个文件时at91rm9200启动所需要的三个bin,他们的实现代 码并不难。
如果是你是采用at91rm9200的评估版,应该能得到其源码。

loader.bin 执行流程,这个文件主要在片内启动从串口下载代码时会用到
loader/entry.S init cpu
b main ---> crt0.S
--> copydata --> clearbss--> b boot
main.c --> boot -->


pAT91 = AT91C_ROM_BOOT_ADDRESS;


--> pAT91->OpenSBuffer
--> pAT91->OpenSvcXmodem

---> AT91F_AIC_ConfigureIt

AT91F_AIC_EnableIt
AT91F_DBGU_Printk("XMODEM: Download U-BOOT ");

Jump.S
// Jump to Uboot BaseAddr exec
Jump((unsigned int)AT91C_UBOOT_BASE_ADDRESS)

boot.bin执行流程 该文件会在从片内启动时被下载到板子上,以后还会被烧写到片外Flash中,以便在片外启动时
用它来引导并解压u-boot.bin.gz,并跳 转到u-boot来执行。
boot/entry.S
b main --> crt0.S --> copydata--> clearbss --> b boot

AT91F_DBGU_Printk(" ");
AT91F_DBGU_Printk("************************************** ");
AT91F_DBGU_Printk("** Welcome to at91rm9200 ** ");
AT91F_DBGU_Printk("************************************** ");

boot/misc.s
----> decompress_image(SRC,DST,LEN)--> gunzip

//jump to ubootBaseAddr exec这里跳转到解压u-boot.bin.gz的地址处直接开始执行u-boot
asm("mov pc,%0" : : "r" (DST));

u-boot.bin执行流程
u-boot/cpu/at91rm9200/start.S
start --->reset
---> copyex ---> cpu_init_crit
---> --> start_armboot
u-boot/lib_arm/board.c

init_fnc_t *init_sequence[] = {
cpu_init,
board_init,
interrupt_init,
env_init,
init_baudrate,
serial_init,
console_init_f,
display_banner,
dram_init,
display_dram_config,
checkboard,
NULL,
};

---> start_armboot ---> callinit_sequence
---> flash_init -->display_flash_config
---> nand_init --->AT91F_DataflashInit
---> dataflash_print_info -->env_relocate
---> drv_vfd_init --> devices_init--> jumptable_init
---> console_init_r --> misc_init_r--> enable_interrupts
---> cs8900_get_enetaddr -->board_post_init -->

u-boot/common/main.c
for (;;)
{
main_loop () --> u_boot_hush_start--> readline
--> abortboot
-->printf("Hit any key to stop autoboot: %2d ",bootdelay);
}

以上是at91rm9200启动并进入u-boot的执行流分析。后面u-boot还会将uImage解压到特定的位置并开始执行内核代码。
 
 
u-boot-1.1.1的移植
自己先用u-boot-1.1.1,主要步骤如下:
 
(1)下载u-boot-1.1.1
http://sourceforge.net/projects/u-boot
 
(2)解压
用户:armlinux
$mkdir bootloader
$cd bootloader
$tar jxvf../source/u-boot-1.1.1.tar.bz2
$cd u-boot-1.1.1
 
(3)修改
首先看一下结构
$ tree -L 1 -d
.
|--board  平台依赖,存放电路板相关的目录文件
|-- common  通用多功能函数的实现
|--cpu  平台依赖,存放cpu相关的目录文件
|--disk  通用。硬盘接口程序
|-- doc  文档
|-- drivers  通用的设备驱动程序,如以太网接口驱动
|-- dtt
|-- examples  应用例子
|-- fs  通用存放文件系统的程序
|-- include 头文件和开发板配置文件,所有开发板配置文件放在其configs里
|-- lib_arm  平台依赖,存放arm架构通用文件
|-- lib_generic  通用的库函数
|-- lib_i386  平台依赖,存放x86架构通用文件
|-- lib_m68k  平台依赖
|--lib_microblaze  平台依赖
|-- lib_mips  平台依赖
|--lib_nios   平台依赖
|-- lib_ppc平台依赖,存放ppc架构通用文件
|-- net  存放网络的程序
|-- post  存放上电自检程序
|-- rtc  rtc的驱动程序
`-- tools  工具
 
 
然后具体步骤为:
 
(一)在board文件夹下面建立自己的开发板的文件夹。一般的,要选取与自己的开发板硬件设置最为接近的型号。在u-boot-1.1.1中,已经支持at91rm9200,所以可以选取at91rm9200dk作为模板进行修改。设置你的开发板的名字,随意即可,我的设置为:myboard。
[armlinux@lqm u-boot-1.1.1]$ cdboard
[armlinux@lqm board]$ cp -Rat91rm9200dk/ myboard/
[armlinux@lqm board]$ cd myboard
[armlinux@lqm myboard]$ ls
at91rm9200dk.c  config.mk flash.c  Makefile u-boot.lds
 
(二)可以看到,这里共有5个文件。
 
首先,要修改主文件的名字,即要把at91rm9200dk.c更改为myboard.c。
其次,要更改config.mk中TEXT_BASE的数值,与loader等一级bootloader的要一致。
接下来,因为在at91rm9200dk用的是AMD的flash,而我的开发板上用的是Intel的28F640J3,那么需要另外找Intel的flash.C,以减少工作量。在这里,推荐用sourceinsight这个查看代码的工具。我是在win下面使用的,它可以很方便的读代码,并且查找调用函数等等的工作。在strongARM构架里有xm250,它的flash是Intel的,修改的东西并不是很多。需要注意的是,xm250的flash位宽是32,而我的位宽是16,要根据这个进行相应的修改。
最后,修改Makefile,主要是修改生成文件的名字。具体操作如下:

[armlinux@lqm myboard]$ mvat91rm9200dk.c myboard.c
[armlinux@lqm myboard]$ cat config.mk
TEXT_BASE =0x21f80000
[armlinux@lqm myboard]$ viconfig.mk
修改成:TEXT_BASE =0x21f00000,然后保存退出。
[armlinux@lqm myboard]$ viMakefile
include$(TOPDIR)/config.mk
LIB    = lib$(BOARD).a
OBJS   := myboard.oflash.o
SOBJS   :=
$(LIB): $(OBJS) $(SOBJS)
       $(AR) crv $@ $(OBJS) $(SOBJS)
clean:
       rm -f $(SOBJS) $(OBJS)
[armlinux@lqm myboard]$ rmflash.c
[armlinux@lqm myboard]$ cp ../xm250/flash.c ./
[armlinux@lqm myboard]$ ls
config.mk  flash.c Makefile  myboard.c u-boot.lds
[armlinux@lqm myboard]$ vi flash.c
 
    34 #undefFLASH_PORT_WIDTH32   
    35 #defineFLASH_PORT_WIDTH16 
   216        switch (value) {
    217
   218        case (FPW) INTEL_ID_28F128J3A:
   219                info->flash_id += FLASH_28F128J3A;
   220                info->sector_count = 128;
   221                info->size =0x01000000;
   222                break;                         

   223
   224        case (FPW) INTEL_ID_28F640J3A   
   225                info->flash_id += FLASH_28F640J3A;
   226                info->sector_count = 64;
   227                info->size =0x00800000;
   228                break;                         
 
[armlinux@lqm myboard]$ cd../..
[armlinux@lqm u-boot-1.1.1]$ vi Makefile
#########################################################################
## AT91RM9200 Systems
#########################################################################
at91rm9200dk_config         unconfig
       @./mkconfig $(@:_config=) arm at91rm9200 at91rm9200dk
myboard_config      unconfig
       @./mkconfig $(@:_config=) arm at91rm9200 myboard
#########################################################################
在这里,可以在命令模式下输入“/at91rm9200”快速查找at91rm9200dk,仿照它的例子,写出自己板子的配置。注意的是,第二行开头要用TAB键,不是空格,否则报错。选项arm表示目标板架构,at91rm9200表是片上系统,myboard是你自己的开发板名字。
[armlinux@lqm u-boot-1.1.1]$ viMAKEALL
LIST_ARM9="    \
       at91rm9200dk   integratorcp integratorap                   \
       omap1510inn    omap1610h2     omap1610inn                    \
       smdk2400       smdk2410       trab                           \
       VCMA9          versatile      myboard                        \
"
(三)修改主要的配置文件。配置选项比较多,主要是配置cpu,波特率,flash和sdram的类型大小,环境变量的偏移量等等,容易出错。应该首先了解硬件情况,仔细对应芯片资料进行修改。
[armlinux@lqm u-boot-1.1.1]$ cdinclude/configs
[armlinux@lqm configs]$ cp at91rm9200dk.h myboard.h
[armlinux@lqm configs]$ vi myboard.h
41 #define CONFIG_MYBOARD        目标板
65 #defineCONFIG_BOOTDELAY      u-boot延时等待时间
110 #defineCONFIG_NR_DRAM_BANKS1   sdram banks,我的是一个
111 #define PHYS_SDRAM0x20000000   sdram 起始地址
112 #define PHYS_SDRAM_SIZE 0x2000000 sdram容量32MB
121 #undefCONFIG_HAS_DATAFLASH    未用dataflash
128 #define PHYS_FLASH_10x10000000
129 #define PHYS_FLASH_2 0x00000000  定 义,flash.c用到,但实际并未起作用
130 #define PHYS_FLASH_SIZE 0x800000 flash容量8MB
131 #defineCFG_FLASH_BASE         PHYS_FLASH_1 flash起始地址别名
132 #define CFG_MAX_FLASH_BANKS1   flash最大banks数
133 #define CFG_MAX_FLASH_SECT64   扇区总数
134 #definePHYS_FLASH_SECT_SIZE   (128*1024)  每个扇区128KB
135 #defineCFG_FLASH_ERASE_TOUT   (2*CFG_HZ)
136 #defineCFG_FLASH_WRITE_TOUT   (2*CFG_HZ)
137 #defineCFG_FLASH_UNLOCK_TOUT  (2*CFG_HZ)
138
139 #undef  CFG_ENV_IS_IN_DATAFLASH
140
141 #ifdef CFG_ENV_IS_IN_DATAFLASH
142 #define CFG_ENV_OFFSET 0x20000
143 #define CFG_ENV_ADDR (CFG_DATAFLASH_LOGIC_ADDR_CS0 +CFG_ENV_OFFSET)
144 #define CFG_ENV_SIZE 0x2000 
145 #else
146 #defineCFG_ENV_IS_IN_FLASH    1
147 #define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x7e0000
148 #define CFG_ENV_SIZE 0x20000 环境变量占了一个扇区,共128KB
149 #endif
150
151 #defineCFG_SOFT_RESET         定义软复位,flash.c用到
152 #define CFG_LOAD_ADDR 0x21000000 
160 #define CFG_PROMPT"U-boot> " 提示符名字,可任意改
 
[armlinux@lqm configs]$ cd../..
[armlinux@lqm u-boot-1.1.1]$make myboard_config
Configuring for myboard board...
[armlinux@lqm u-boot-1.1.1]$ makeCROSS_COMPILE=arm-linux-
然后把生成的u-boot.bin保存,并且压缩一下得到u-boot.bin.gz。将这两个文件通过ftp传至windows上,通过SecureCRT来进行传输。
这里注意,知道CROSS_COMPILE路径,前面设置环境变量时说到过。压缩命令为gzip<filename>
利用交叉线将com1和开发板串口相连。首先设置为片内启动方式,上电。超级终端首先出现“CCCC”,这时利用modem协议传输loader.bin,成功后传输u-boot.bin。具体现象如下:
--------------------------------------------------------------
CCCCCCCCCCCC
正在开始 xmodem 传输。 按 Ctrl+C 取消。
正在传输 loader.bin...
 100%      6 KB
-I- AT91F_LowLevelInit(): Debugchannelinitialized    6KB/s00:00:01      0 错误
loader 1.0(Aug  8 2003 - 12:01:07)
XMODEM: Download U-BOOT
CCCCCCCCCCCCC
正 在开始 xmodem 传输。 按 Ctrl+C 取消。
正在传输 u-boot.bin...
 100%     85 KB    6 KB/s00:00:14      0 错误

U-Boot downloadedsuccessfully

U-Boot 1.1.1 (Aug 17 2006 -14:07:56)
U-Boot code: 21F00000-> 21F156CC  BSS: ->21F198D0
RAM Configuration:
Bank #0: 20000000 32 MB
Flash:  8 MB
*** Warning - bad CRC, using default environment
In:   serial
Out:   serial
Err:   serial
U-boot> version
U-Boot 1.1.1 (Aug 17 2006 -14:07:56)
U-boot>printenv
bootdelay=5
baudrate=115200
stdin=serial
stdout=serial
stderr=serial
Environment tes
-------------------------------------------------------
设定环境变量,当然这些也可以在include/configs/<your-board>.h里面定义。
U-boot> setenv ipaddr 192.168.1.100
U-boot> setenv serverip 192.168.1.106
U-boot> setenv ethaddr36:B9:04:00:24:80
注意:物理地址应该合法,在tools文件夹内有一个文件gen_eth_addr.c,利用其生成可执行文件则能够获得有效的mac地址。你可以先用gcc编译,生成可执行文件,然后执行,获得合法的mac地址。
U-boot> saveenv
Saving Environment to Flash...
Un-Protected 1 sectors
Erasing Flash...
Erasing sector done
Erased 1 sectors
Writing to Flash...\done
Protected 1 sectors
U-boot> tftpboot20000000 boot.bin
TFTP from server 192.168.1.106; our IP address is192.168.1.100
Filename 'boot.bin'.
Load address: 0x20000000
Loading: ###
done
Bytes transferred = 10628 (2984 hex)
U-boot> protectoff 1:0
Un-Protect Flash Sectors 0-0 in Bank # 1
U-boot> erase 1:0
Erase Flash Sectors 0-0 in Bank # 1
Erasing sector  0 ...  done
U-boot> cp.b 20000000 10000000 2984
Copy to Flash...-done
U-boot> tftpboot20000000 u-boot.bin.gz
TFTP from server 192.168.1.106; our IP address is192.168.1.100
Filename 'u-boot.bin.gz'.
Load address: 0x20000000
Loading: #########
done
Bytes transferred = 43791 (ab0f hex)
U-boot> cp.b 20000000 10010000 ab0f
Copy to Flash...\done
断电重启,从片外启动。
 
这时遇到了一个问题,就是从flash启动时,总是提示:***Warning - bad CRC, using defaultenvironment,具体解决方法,看我的blog的文章。解决后,重新编译就可以了。
U-Boot 1.1.1 (Aug 17 2006 -16:50:31)
U-Boot code: 21F00000-> 21F157F4  BSS: ->21F199F4
RAM Configuration:
Bank #0: 20000000 32 MB
Flash:  8 MB
In:   serial
Out:   serial
Err:   serial
U-Boot>
经验证,这是u-boot-1.1.1已经能够正常启动了。
---------------------------
同样的方法,u-boot-1.1.2也正常启动了。另外,u-boot-1.1.2有几个小的补丁,等明天再做一下总结。同时看看如何制作补丁,如何打补丁。具体的调试过程没有写得很仔细,要想做好一项工作,只会写程序远远不够,更为重要的是会调试。我需要加强此方面的工作。明天把JEDIprobe调试环境的建立也总结一下。
2006-08-18
今天学习了一下Linux下面patch的制作和使用,做了总结,放到blog上面。u-boot-1.1.2有几个diff补丁文件,具体没有分析,先附在这里。我的使用倒是还没有发现这几个问题,也许没有测试,不管它,以后如果出现问题在来仔细考虑吧。
开发板由王老师用,我先学习内核裁减吧。关于移植版本,不一定非得越高越好。关于内核版本标号问题,详细参考《Building Embedded LinuxSystems》。现在还不开发产品,那么先多试用几个,总结总结经验。初步打算先移植一个2.4.x版本,然后移植一个2.6.x版本。
-----------------------------
Bug1:
RCS /home/cvs/u-boot/tools/env/fw_env.c,v
retrieving revision 1.2
diff -u -r1.2 fw_env.c
--- fw_env.c 21 Jul 2004 03:28:43-0000 1.2
+++ fw_env.c 23 Jul 2004 05:00:25 -0000
@@ -612,8 +612,8 @@
   if (!crc1_ok){
    fprintf(stderr,
     "Warning:Bad CRC, using default environment\n");
  environment.data= default_environment;
  free(addr1);
  memset(environment.data,0, ENV_SIZE);
  memcpy(environment.data,default_environment, sizeof(default_environment));
   }
  } else {
   flag1 =environment.flags;
Bug2:
saveenv bad checksum
when saving environment after changing stdin,
stdout,... the checksum is not consistent.
Adding an env_crc_update() before saving environment
could solve this. i.e in common/cmd_nvedit.c in
do_saveenv() :
int do_saveenv (cmd_tbl_t*cmdtp, int flag, int argc,char *argv[])
{
extern char * env_name_spec;
printf ("Saving Environmentto %s...\n", env_name_spec);
env_crc_update();