前段时间移植了vivi-0.1.4,也对源代码进行了解析学习。原本的想法是给vivi增加tftp功能,那么就需要写cs8900a驱动(我用的网卡芯片是CS8900A-CQ3Z),然后呢实现tftp协议,最后添加到vivi支持的命令集中。这部分工作如果从头开发,没有必要,因为U-boot就提供了tftp功能,可以借鉴,把相关代码移植到vivi下,这样vivi就具备了tftp下载功能。所以,准备先移植uboot,学习一下。vivi和uboot互相利用,进行功能完善和理解的深入。
【备注: 2007年末就是专心研究bootloader相关技术,以vivi和U-boot进行对比研究,是一个很好的学习思路。两者可以同时进行,互相借鉴,有助于问题的解决。这仅仅是学习的方法,并不是工作开发的方法。毕竟工作中是没有太多的时间让你细致的研究相关的代码的。工作中就是要尽可能快的寻找一切可以有效利用的资源,然后整理吸收,在这个高度上完成自己的工作,绝对不能自大的一切从头做起。】
下面只关注移植流程和解决方案,自己所作的工作量很少,结合的代码分析也比较少,主要解决出现的问题。后续的工作中,会结合uboot源代码分析学习。继续加深对bootloader技术的认识!
一、前言
s3c2410在国内还是用的很广泛的,所以资料相对比较多。uboot对基于nand flash启动也提供了支持,相关的移植步骤和资料也比较多。我推荐的方法还是通过读patch来分析解决移植问题。这里主要提到几个参考资料:
1、openmoko
网上原创性的解决方案,估计大多数源于openmoko。看看网上那些资料,所用的源代码和思路无一不是来自这里的patch,最多根据自己的开发板做了少许的改动。现在把openmoko的资源列表如下:
wiki openmoko主页网址:
wiki openmoko bootloader:
wiki openmoko uboot patches:
上面的资源非常丰富,只要有效的利用,能解决遇到大部分通常的问题。
2、嵌入式中国
北邮的hiboy在u-boot-1.2.0的移植上有不少独创性的工作。
lufuchong也做了很多的工作,利用了hn的keety的补丁。不过我没有找到他的补丁,对其关于bootm的理解还是赞一个。
其他的资料就不一一列出了,最有价值的就是上面三位的工作了。
利用patch是很好的方法,当然我不是说直接打上补丁,而是阅读patch,通过patch把移植的思路和步骤理清理顺,然后形成自己的理解,最后可以深入源代码,增加自己的贡献。如果说我在s3c2410上做了些工作,那就是强调和利用patch,好的patch是最好的资源,即使没有详细的说明,有一定移植经验的人也很容易借鉴,并最终成功。如果对patch不了解,就先看一下我在去年暑假翻译的一篇文章:
http://blog.chinaunix.net/u/21948/showart_157145.html《Linux下patch的制作和使用》。需要注意的是,在制作patch时,一定要用distclean清理一下源文件树,否则的话,制作的patch质量上可是不敢恭维。既然要做,就要做好一些。hiboy提供的patch中,就犯了这个错误,希望不是习惯问题。
二、准备工作
1、选择版本
版本虽然不是越新越好,但是新版本提供的特性较多,自己能够学习到的内容也比较多,所以还是选择最新版本。
[armlinux@lqm bootloader]$ ftp ftp.denx.de Connected to .
|
还是从pub/u-boot下载最新版本,现在正式发布版是u-boot-1.2.0。以后就以此版本进行学习和开发。解压等工作不必细说。
为了制作patch的方便,解压之后的u-boot-1.2.0命名为u-boot-1.2.0.orig,然后复制做一个开发版u-boot-1.2.0。为了在命令行下操作方便,可以使用软链接。如下:
[armlinux@lqm bootloader]$ cp -rf u-boot-1.2.0.orig/ u-boot-1.2.0 [armlinux@lqm bootloader]$ ln -s u-boot-1.2.0.orig/ orig [armlinux@lqm bootloader]$ ln -s u-boot-1.2.0 develop
|
2、交叉编译工具链
u-boot-1.2.0的版本还是比较高的,去年暑假自己做过交叉编译工具链,耗费工作量太大。兴趣也不在那里,所以还是选择已有的质量较高的工具链。还是到ARM的官方网站上找,可以找到CODESOURCERY公司提供高质量的GNU Toolchain,你可以从这里下载:。最新版已经是arm-2007q1。我把交叉编译工具都放到/usr/local/arm/下面了,现在只有两个:
[armlinux@lqm arm]$ tree -L 1 . |-- 2.95.3 `-- arm-2007q1
2 directories, 0 files
|
大多数非最新版使用2.95.3可以解决了,新版本基本采用arm-2007q1。这两个工具都是比较成熟好用的,可以避免出现不少问题。
3、硬件配置说明
实验箱还是深圳Embest的EDUKIT-III,资源如下:
·SoC : S3C2410A
·SDRAM: 两片HY57V561620CT-H(共64M)
·NOR Flash : AM29LV160DB-90EC(2M)
·NAND Flash: K9F5608UOC(32M)
·网络芯片: CS8900A-CQ3Z(接在nGCS3,也就是bank3,由此对应的基地址为0x19000300)
可见大部分是smdk2410的标配,所以移植的工作量是很小的。只是在流程上弄清楚,在分析完源代码后,可以考虑增加或者改进功能。现在的想法是暂时不使用nor flash,直接使用nand flash,跟前面vivi的开发保持一致。
(备注:
从U-boot-1.2.0可以看出,U-boot的开发已经不仅仅满足于作为一个bootloader,现在正在逐步在下面几个方面深入和完善:增加下载手段和对文件系统的支持度、增加内核调试功能(集成debugger)、完善对多architecture多硬件平台的支持。从这个角度上看,U-boot已经身兼bootloader、monitor、debugger多重功能,支持的力度也越来越广泛。这是bootloader技术发展的一个趋势,慢慢的庞大起来,如同Linux内核一样,不再小巧。与此同时,我们可以从中学习和认识的东西也在不断增多。
我想现在bootloader的设计分成三种趋势。第一种是只要求具备基本的bootloader功能,对性能大小要求非常高,这样需要专门编写。归结为“微型化”。第二种是利用现成的通用的bootloader,移植到自己的开发板上,比如U-boot就是一个很好的选择。在这方面,U-boot已经从bootloader的基本功能向可能扩展的各个方向延伸,可归结为“大型化”。第三种,就是SoC厂商为了推广自己的产品,在推出时,可能会开发专用的bootloader,功能比较完善,但是对其他平台的支持并不好,如vivi、blob都在此范围内。它介于上述两者之间。
)
三、移植工作
(一)首先就是让U-boot能跑起来
这部分的工作比较少,参考的主要是openmoko的uboot-s3c2410-nand.patch,通过读这个patch理顺移植的思路。因为前面做at91rm9200的时候用过uboot1.1.2,所以对uboot的整个结构和移植的思路还有一定了解的。假定我们的开发板命名为myboard,与smdk2410基本类似。往常我的做法也是修改uboot,使之支持myboard,而针对smdk2410是没有变化的。现在为了使patch更容易阅读,与源代码的修改更加明确,就默认smdk2410就是myboard,直接在上面动手术。这样,通过patch可以把修改的步骤看的一清二楚。
主要的步骤有这么几个:
·修改顶层Makefile,更改CROSS_COMPILE为你的交叉编译工具的路径。
这步工作并非必须,你也可以在命令行中指定。不过那样就麻烦了些。
·修改board/{your board}/
这是主要的工作量,board目录下是平台依赖,存放电路板相关的文件。重点是内存初始化和flash驱动、开发板初始化。
·修改cpu/arm920t/
这里存放的是cpu相关的目录文件,启动的入口地址就是在start.S中。需要做适当的修改。
·修改include/configs下相关配置文件
这里是修改配置文件,对smdk2410来说,就是smdk2410.h。主要是根据自己需要的功能进行定制customize,也可以称之为裁减。
1、与处理器架构或开发板硬件相关
2、一些通用的函数或者驱动程序
3、uboot的应用程序、工具或者文档
下面开始移植。
第一步工作,修改顶层目录下的Makefile。
这里的基本工作就是修改CROSS_COMPILE,比较简单。网上通常的流程(以smdk2410为例)为:
为什么要这样做,还有什么可以执行的make命令。在这里还是简单的阅读一下Makefile,对整体规划有了初步的了解。其中第一条命令源于(以smdk2410为例),属于指定目标编译:
smdk2410_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
|
其中依赖部分unconfig的作用是清理一下垃圾文件。
unconfig: @rm -f $(obj)include/config.h $(obj)include/config.mk \ $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
|
而MKCONFIG是一个脚本文件,可以从下看出:
MKCONFIG := $(SRCTREE)/mkconfig
|
继续向上追SRCTREE:
到此就是终结了。CURDIR这个变量是Makefile提供的,代表了make当前的工作路径。也就是说在顶层目录下有一个mkconfig脚本文件。如果不清楚变量到底是什么,提供的调试手段就是在Makefile的底部加入调试单元,比如:
# # make debug # debug: @echo "CRUDIR: $(CURDIR)" @echo "SRCTREE: $(SRCTREE)" @echo "OBJTREE: $(OBJTREE)"
|
这样就可以清楚的看到每个变量代表的内容了。追查到这里,就很清楚了,如果你的第一步工作是make smdk2410_config,那么所进行的工作就是清理一下临时文件,然后执行mkcofig这个shell脚本。脚本的内容就不具体分析了,比较简单,其实就是通过你的配置部分完成include/config.mk的生成,里面有四个宏,这是根据你的配置来的。例如:
ARCH = arm CPU = arm920t BOARD = smdk2410 SOC = s3c24x0
|
具体的含义很明显了。这样第二步的工作是make,其实按照make的执行规则就是执行make all。如果你前面指定了CROSS_COMPILE,那么第二步工作只需要执行make就可以了,不需要在命令行指定ARCH=arm,也不需要在Makefile中指定ARCH。这些工作mkconfig会替你去做。你需要做的只是完成配置命令部分。
为了是测试流程自动化,借鉴vivi的Makefile,我增加了一个make命令,这样只需要执行make smdk2410,就可以完成三步工作:一是make distclean,二是make smdk2410_config,三是make。第一部分patch如下:
[armlinux@lqm bootloader]$ cat uboot_topdir_makefile.patch diff -urN u-boot-1.2.0.orig/Makefile u-boot-1.2.0/Makefile --- u-boot-1.2.0.orig/Makefile 2007-01-07 07:13:11.000000000 +0800 +++ u-boot-1.2.0/Makefile 2007-09-19 12:09:20.000000000 +0800 @@ -125,7 +125,7 @@ CROSS_COMPILE = powerpc-linux- endif ifeq ($(ARCH),arm) -CROSS_COMPILE = arm-linux- +CROSS_COMPILE = /usr/local/arm/arm-2007q1/bin/arm-none-linux-gnueabi- endif ifeq ($(ARCH),i386) ifeq ($(HOSTARCH),i386) @@ -2350,3 +2350,10 @@ gtar --force-local -zcvf `date "+$$F-%Y-%m-%d-%T.tar.gz"` $$F ######################################################################### + +# +# make {your board} +# + +%: distclean %_config + $(MAKE) && echo "^_^ Succeed!"
|
第二步工作:修改board的相关文件
一是修改lowlevel_init.S,就是完成13个内存寄存器的配置。前面在vivi的基础实验中也做过了。这里最为关键的部分其实是BWSCON,要配置好BANK3的总线时序。如果此处的总线时序配置不好,那么CS8900A是无法正常工作的。因为EDUKIT-III完全按照smdk2410的配置,片选为nGCS3,也就是BANK3,基地址仍然为0x19000300。基本不需要修改,如果是其他的网络芯片,一定要注意设置此处的总线位宽和总线时序,否则,网络芯片无法正常工作。我在这里的工作是调整了sdram的刷新频率,具体为:
#define REFCNT 1268 /* period=7.8125us, HCLK=100Mhz, (2048+1-7.8125*100) */
|
但是,这样的前提是HCLK必须为100MHz。这就需要修改smdk2410.c了,同时还要根据蜂鸣器等等,设置合适的GPIO的数值。可以参考patch。
因为是从nand flash启动,需要用到nand read,可以直接把vivi中的nand_read.c复制过来,增加一个配置选项CONFIG_S3C2410_NAND_BOOT。按照uboot的配置参数的命名原则,CONFIG_和CFG_是不同的。需要注意一下。
完成这些,修改一下Makefile就可以了。这里面最为困难的就是要配置好内存寄存器,设置好总线时序。网卡驱动的关键性工作也在这个地方,软硬件都理解才能顺利解决。
|
文件: |
uboot_board_s3c2410.patch.gz |
大小: |
1KB |
下载: |
下载 | |
第三步工作:修改cpu/arm920t相关文件
主要就是修改start.S。而start.S的核心工作就是增加copy_myself。这个可以借鉴vivi的部分,不过需要根据uboot的一些特点做一些修改。也不用多说。补丁如下:
|
文件: |
uboot_cpu_s3c2410.patch.gz |
大小: |
3KB |
下载: |
下载 | |
第四步工作:修改配置文件
|
文件: |
uboot_include_s3c2410.patch.gz |
大小: |
3KB |
下载: |
下载 | |
注意,上述的每个补丁都包含前面所做的工作。也就是说,最后的补丁uboot_include_s3c2410.patch.gz是完成基本工作后的补丁。
编译得到u-boot.bin,利用JTAG工具烧写nand flash,上电后从nand flash启动:
U-Boot 1.2.0 (Sep 19 2007 - 12:43:31)
DRAM: 64 MB Flash: 512 kB *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial U-boot # printenv bootdelay=3 baudrate=115200 ethaddr=08:00:3e:26:0a:5b ipaddr=192.168.1.110 serverip=192.168.1.216 netmask=255.255.255.0 stdin=serial stdout=serial stderr=serial
Environment size: 161/65532 bytes U-boot # ping 192.168.1.216 host 192.168.1.216 is alive
|
测试了一下printenv命令和ping命令,都正常。然后又测试了date命令,如下,也正常:
U-boot # date 091916122007 Date: 2007-09-19 (Wednesday) Time: 16:12:00 U-boot # date Date: 2007-09-19 (Wednesday) Time: 16:12:03
|
U-boot # tftp 0x31000000 uImage TFTP from server 192.168.1.216; our IP address is 192.168.1.110 Filename 'uImage'. Load address: 0x31000000 Loading: ################################################################# ################################################################# done Bytes transferred = 662340 (a1b44 hex) U-boot # bootm 0x31000000 ## Booting image at 31000000 ... Image Name: linux-2.4.18 Created: 2007-09-18 5:01:45 UTC Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 662276 Bytes = 646.8 kB Load Address: 30008000 Entry Point: 30008000 Verifying Checksum ... OK OK
Starting kernel ...
Uncompressing Linux................................................ done, booting the kernel. Linux version 2.4.18-rmk7-pxa1 (armlinux@lqm) (gcc version 2.95.3 20010315 (release)) #1 Tue Sep 18 12:59:07 CST 2007
//下面省略
|
看来是成功的。
注意到一个问题,原来用uboot1.1.2的时候,会打印U-Boot code: ,但是现在没有。使用source insight查看lib_arm中的board.c的init_sequence数组,经过查找,应该在display_banner里面:
/* * To match the U-Boot user interface on ARM platforms to the U-Boot * standard (as on PPC platforms), some messages with debug character * are removed from the default U-Boot build. * * Define DEBUG here if you want additional info as shown below * printed upon startup: * * U-Boot code: 00F00000 -> 00F3C774 BSS: -> 00FC3274 * IRQ Stack: 00ebff7c * FIQ Stack: 00ebef7c */
|
通过debug可以知道,uboot取消了额外的调试信息,追查到【include/common.h】中,看看这个部分的定义:
#ifdef DEBUG #define debug(fmt,args...) printf (fmt ,##args) #define debugX(level,fmt,args...) if (DEBUG>=level) printf(fmt,##args); #else #define debug(fmt,args...) #define debugX(level,fmt,args...) #endif /* DEBUG */
|
也就是说,你只要在这里定义一下DEBUG,把开关打开就可以看到调试信息了,上面的注释解释的也非常明确。我想打印调试信息,所以增加了DEBUG,并且修正了patch(当然你也可以不要这个debug信息)。注意,要在include 前增加DEBUG的定义,原因很简单。于是现在的补丁如下:
|
文件: |
uboot-s3c2410-nand.patch.gz |
大小: |
3KB |
下载: |
下载 | |
uboot.bin下载后,上电启动打印信息如下:
U-Boot 1.2.0 (Sep 19 2007 - 13:07:41)
U-Boot code: 33F80000 -> 33F96C74 BSS: -> 33F9B3A4 RAM Configuration: Bank #0: 30000000 64 MB Flash: 512 kB *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial U-boot #
|
比较好用了。
(二)下面的工作就是去掉flash配置部分,然后增加nand读写部分。这里需要参考hiboy的patch和openmoko的default-env.patch,另外需要关注的就是uboot自带的文档,在doc中,关于nand部分有两篇有价值的参考。
|
文件: |
uboot-s3c2410-nand.patch.gz |
大小: |
6KB |
下载: |
下载 | |
先给出patch,明天再总结吧。主要就是关于legacy的使用方法、nand的底层驱动、default env的修正三个方面。现在的启动信息如下:
U-Boot 1.2.0 (Sep 19 2007 - 13:54:19)
U-Boot code: 33F80000 -> 33F97950 BSS: -> 33F9C200 RAM Configuration: Bank #0: 30000000 64 MB NAND: 32 MB In: serial Out: serial Err: serial U-boot #
|
测试了nand部分,效果还可以,一切正常。用bootm引导内核也没有问题,还不能挂载文件系统。如果把文件系统挂载弄好,那bootloader就算是彻底移植好了。争取把tftp部分移植到vivi上面。
U-boot # nand info
Device 0: Samsung KM29U256T at 0x4e000000 (32 MB, 16 kB sector) U-boot # printenv baudrate=115200 ethaddr=08:00:3e:26:0a:5b netmask=255.255.255.0 ipaddr=192.168.1.110 serverip=192.168.1.216 bootargs=noinitrd root=/dev/bon/2 console=ttyS0 bootdelay=5 stdin=serial stdout=serial stderr=serial
Environment size: 209/131068 bytes U-boot # setenv bootargs 6 U-boot # saveenv Saving Environment to NAND... Erasing Nand...Writing to Nand... done ?boot # reset U-Boot 1.2.0 (Sep 19 2007 - 13:54:19)
U-Boot code: 33F80000 -> 33F97950 BSS: -> 33F9C200 RAM Configuration: Bank #0: 30000000 64 MB NAND: 32 MB In: serial Out: serial Err: serial U-boot # printenv baudrate=115200 ethaddr=08:00:3e:26:0a:5b netmask=255.255.255.0 ipaddr=192.168.1.110 serverip=192.168.1.216 bootdelay=5 bootargs=6 stdin=serial stdout=serial stderr=serial
Environment size: 172/131068 bytes U-boot #
|