公司的项目用的是扬创的2440开发板。此板仅有u-boot.bin提供,而没有u-boot的源码,我依照开发板提供的电路图,根据公司项目的要求,对其电路进行了修改,添加,并重新绘制了印制板,用的是扬创的核心板加自已的底板的构架。硬件调试完毕后,问题来了,我需要在硬件一启动时,就要对某些口线进行初始化,可是因为扬创没有提供U-boot的源码,只好自已动手去移植一套源码了。
移植过程主要是根据网上一名为tekkaman(日本动画,宇宙骑士的主角,看来,此兄是一动漫迷)的高手提供的方法进行的,他不仅提供了方法,还把移植好的u-boot 1.3.1放在网上供人下载,真是要感谢他了。移植过程基本顺利。不过还是有一些问题,我将这此记录下来,以供参考。
移植时,tekkaman提供的代码解压,用其中的文件拷贝到原版的u-boot1.3.1目录中,如提示是否覆盖原文件,选覆盖。按照他的方法,对其进行编译配置,这步顺利完成。然后,编译,我用的是arm-linux 3.4.1,编译报错,又试用了3.3.2,2.95.3,均报错。查了资料,知道这是u-boot的浮点数类型引起,于是自已编译了一新的arm-linux 4.1版,是用crosstool0.43编译的。编译过程很顺利。完了,再用新编译的arm-linux4.1版对u-boot1.3.1编译,顺利通过。因为我的板子上是可以正常运行u-boot1.2的(扬创公司提供的u-boot),为了方便u-boot1.3.1调试,我想将u-boot1.3.1用1.2下载到内存中运行。查了网上的相关资料,试了多次,总算可以在内存中运行了,方法很简单,将/root/u-boot-1.3.1/board/tekkaman/tekkaman2440目录下的u-boot.lds文件中的text_base改为0x33000000,再将/root/u-boot-1.3.1/cpu/arm920t中的start.s中
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
此段代码中的bl cpu_init_crit注释掉,即不进行CPU的初始化工作(此工作,当前在板子上运行的u-boot1.2已完成,故不能再次进行),即改为
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
@bl cpu_init_crit
#endif
在下面一段代码中增加一些语句
#ifdef CONFIG_S3C2440_NAND_BOOT
@ reset NAND
mov r1, #NAND_CTL_BASE
ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]
ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control
str r2, [r1, #oNFCONT]
ldr r2, [r1, #oNFCONT]
ldr r2, =(0x6) @ RnB Clear
str r2, [r1, #oNFSTAT]
ldr r2, [r1, #oNFSTAT]
mov r2, #0xff @ RESET command
strb r2, [r1, #oNFCMD]
mov r3, #0 @ wait
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT] @ wait ready
tst r2, #0x4
beq nand2
ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x2 @ Flash Memory Chip Disable
str r2, [r1, #oNFCONT]
@ get read to call C functions (for nand_read())
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp=0
//增加的语句
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
//////////////////////////////
@ copy U-Boot to RAM
ldr r0, =TEXT_BASE
mov r1, #0x0
mov r2, #0x30000
bl nand_read_ll
tst r0, #0x0
beq ok_nand_read
增加的语句是为判断是否是已在内存中运行u-boot,如是,则不进行下面一段将nand flash中的程序拷贝到内存中的操作(此操作在从nand flash中启动时,是必须的,而在内存中运行时,则不能使用,因为此时,nand flash中不一定是要调试的u-boot代码)
编译。完成后,使用tftp将u-boot.bin下载到板子的内存中,注意,内存地址一定是0x33000000,再用u-boot命令go 0x33000000,即可在内存中运行u-boot。解释一下为什么要这么做,u-boot的启动分两个阶段,第一阶段完成一些必须初始工作,此阶段是汇编写的,第二阶段则是进行一些较高级的操作,比如初始化板上的网卡芯片了,引导内核了什么的,这部分是用C写的。第一阶段的汇编程序在编写时,采用的是代码位置无关的方式,即无论代码的开头放在内存的哪一个地址,都可以从这个位置正常运行程序,而不管编译器在编译时认可的代码起始地址是什么。实际上,前面修改的text_base地址,就是编译器所认为的代码起始地址。U-boot中,第一阶段进入第二阶段是直接转入第二阶段的起始地址,而第二阶段的代码编写是与位置有关的,即代码起始地址必须与编译器认可的起始地址一至,才能正常运行。第二阶段的起始地址在编译完成后,即已确定,是相对于text_base的地址。那么我们将代码下载到text_base指定的地址中时,第二阶段代码的头就是在它应该在的位置上了。当我们从此text_base的地址处运行程序时,没有任何问题。而当此代码是从nand flash中运行时,第一阶段的起始地址为0,但因为第一阶段代码是位置无关,所以第一阶段代码可以正常运行,但第二阶段代码的头却不在它应该在的位置了,所以,第二阶段不能正常运行,因为,在第一阶段中,必须将u-boot自身拷贝到text_base的地址处,这样,第二阶段的代码就在它应该在的位置了,此时,第一阶段的程序可以顺利跳转到第二阶段运行了。这个过程,是我看了很资料后总结出来的。
完成此工作后,即可以在内存中运行u-boot了,但因为tekkaman的程序中,用的网卡芯片是DM9000,我用的是CS8900,所以要在tekkaman.h中,将DM9000的宏注释掉,将CS8900的宏开放。在此我犯了个错误,因为我一开始没有修改此处的宏编译的程序,而我在修改过宏以后,没有执行make clean就直接make,结果,网卡不能正常工作,总是报告cs8900 not found,试了多次不能解决,耽搁了一些时间。后来,在make clean后,再make,想不到问题解决了,想来是有些与cs8900想关的文件在修改过宏后没有重新编译所置。真是无语了。
这个问题解决后,就是要用u-boot引导linux内核了,我用的是扬创提供的linux2.6.13的内核,扬创提供的内核,loadaddress和entry都是30008000,我用u-boot1.2中的bootcmd参数,u-boot1.3.1 bootm却不能引导,报bad magic number,看了bootm的相关资料,得知,如果我们没用mkimage对内核进行处理的话,那直接把内核下载到0x30008000再运行就行,内核会自解压运行(不过内核运行需要一个tag来传递参数,而这个tag建议是由bootloader提供的,在u-boot下默认是由bootm命令建立的)。
2)如果使用mkimage生成内核镜像文件的话,会在内核的前头加上了64byte的信息,供建立tag之用。bootm命令会首先判断bootm xxxx 这个指定的地址xxxx是否与-a指定的加载地址相同。
(1)如果不同的话会从这个地址开始提取出这个64byte的头部,对其进行分析,然后把去掉头部的内核复制到-a指定的load地址中去运行之
(2)如果相同的话那就让其原封不同的放在那,但-e指定的入口地址会推后64byte,以跳过这64byte的头部。
Bootm在没有参数时,是采用tekkaman.h中的#define CFG_LOAD_ADDR 的地址的,而我用bootm就是没有使用参数,所以出错了。正确的做法应该是用nand read命令将内核从nand flash中读到内存的某一地址中(注意不要与其它已分配的内存冲突),然后再用bootm 加地址参数,即可引导,也可以在上述的文件中,将CFG_LOAD_ADDR的地址定义为此地址,再用bootm就可以了,我最终就是这么用的。
做完这此,内核可以引导了,但却停在starting kernel不动了,好在我以前做过vivi+linux2.6.22的移植,知道此问题多半是由于mach_type不同而造成的。在u-boot中,此mach_type是由tekkaman.c中的这段代码定义的
#if defined(CONFIG_S3C2440)
/* arch number of S3C2440 -Board */
gd->bd->bi_arch_number = 5244 ; //改为和内核的MACH_TYPE一至
//gd->bd->bi_arch_number = MACH_TYPE_S3C2440 ;
#endif
你可以象我一样直接在这里改数字,也可以在include/asm-arm/mach_types.h的文件中,改MACH_TYPE_S3C2440的数值。将数值改为和内核的mach_type一至。至于内核的mach_type可以在内核linux源代码下的arch/arm/tools中的mach_types文件查看到。
重新编译下载u-boot1.3.1后,内核正常引导了。到此,u-boot1.3.1的移植告一段落。下面,我要做的是移植yaffs,使u-boot1.3.1可以支持yaffs文件的烧写。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/hugerat/archive/2008/10/28/3167903.aspx