第二版主要是对于第一版的一些错误改正,之前nand flash的移植失败,特在此处使用另一种nand flash移植方法.另外在这里还介绍一下uboot支持yaffs烧写功能的移植(新版里已经支持了),还介绍一下yaffs2文件系统的制作与使用。
移植U-Boot 1.3.4到GT2440(第一版)下载地址
具体下载目录在 /2011年资料/嵌入式Linux/移植U-Boot 1.3.4到GT2440/
硬件配置
1、 GT2440\其它开发板
2、 其中nand flash为2Kb一页(具体和512byte的有什么区别,参考nand元件手册,或者上网搜一下,对于uboot,主要是读nand时的写地址时序的不一样)
3、 串行线
4、 J-link\j-tag(笔者用的是jlink,主要用于uboot的调试,因为你移植马上能用的可能性不大,所以需要调试)
软件配置:
1、u-boot-1.3.4
2、- j-link或者H-jtag
Uboot 源码是不支持从nand中启动的,但是2410 2440是支持的,而且对于闪存,nand比较大容量,比较便宜,所以使用nand启动uboot是比较需要的。那么它启动的原理是什么?
其实从nand flash 控制器有一个特殊功能,会自动把nand flash前4K内容复制到4K SRAM中(注意,是只有4k的SRAM而不是SDRAM,超过怎么办,所以要复制到SDRAM中,如下图)中,并把0x00000000设置成内存起始地址,cpu从这个地址开始运行。这个过程不需要程序干涉。在配置NAND启动模式之后,S3C2440上电会先将NAND中的0x0 - 0x1000共4096字节的数据拷贝到位于Bank0中的Boot Internal SRAM上
这4K的内容,主要是保存的uboot的部分功能(拷贝功能),执行后,再把nand里的内容拷贝到SDRAM中,原因有下:
1、 SDRAM运行速度快
2、 实际的uboot代码永远大于4Kb的空间,,所以要开辟一个新空间给uboot运行
二、uboot的运行流程
首先先大概分析一下uboot,这样有利于明白,移植的每一步是需要做些什么?
在讲uboot启动前,先讲一下arm启动流程,arm启动是先运行芯片厂家固化的boot block,这段程序是引导块,芯片厂家将boot block地址重映射到片内存储器空间最高处,接近接近2G(0x8000 0000靠MMU映射)。运行完这段程序后,就会运行0x0 地址。看回上面的2440存储映射图,假如是nor的话,就会直接运行Nor 里的内容,如果是nand的话,nand控制器先拷4k到0x0000 0000里的SRAM,然后0x4000000后的内容会被重映射到0x0000 0000的映射,这样就代表前4k直接操作的是bootinternal的SRAM,而不是nand的前4k,可能是因为SRAM速度快.
上个很好的图:
现在看回uboot启动流程:
像网上说的,uboot编译时首先编译的是u-boot-1.3.4\board\你的开发板文件夹\u-boot.lds,看一个2410的例子:
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
cpu\arm920t\start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
(1) 从ENTRY(_start)可以看出u-boot的入口函数是_start,这个没错
(2) 从. = 0x00000000也许可以看出_start的地址是0x00000000,事实并不是这样的,
.text为代码段,可以看出cpu/arm920t/start.o 在代码段的最前面,所以会先执行start.o 中的代码, 如何设置从0x33f80000开始呢 ~这是链接的时候指定的
在根目录下面的config.mk中有下面一句
LDFLAGS +=-Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)
关键就是其中的-Ttext $(TEXT_BASE),这句指明了代码段的起始地址
而TEXT_BASE在 board/smdk2440/config.mk中定义 TEXT_BASE = 0x33F8 0000
为什么是0x33F80000呢 ~
这是将NAND中Uboot拷贝到RAM中的起始地址,所以在代码拷贝到RAM之前不能使用绝对地址(链接后都会加上_TEXT_BASE)来寻址数据,只能用相对地址(相对于当前PC)(adr r0, _start可以确定程序在哪里运行,因为adr是基于pc当前值的,假如在内存中0x33f8000就应该是0x33f8000+_start,假如是在flash中,就应该是0+_start )
ARM汇编中,常有两种跳转方法:b跳转指令、ldr指令向PC赋值。 (参考《[NAND]UBOOT从NAND FLASH启动分析》)
要特别注意这两条指令的意思:
(a) b step:b跳转指令是相对跳转,依赖当前PC的值,偏移量是通过该
指令本身的 bit[23:0]算出来的,这使得使用b指令的程序不依赖于要跳到的代
码的位置,只看指令本身。具体是将这24位左移两位加上PC再赋给PC寄存器,得到目标地址
(b) ldr pc, =step :该指令是一个伪指令编译后会生成以下代码:
ldr pc, 0x30008000
<0x30008000 > step
是从内存中的某个位置(step)读出数据并赋给PC,同样依赖当前PC的值,但
是偏移量是step的连接地址(运行时的地址),所以可以用它实现从Flash到RAM的程
序跳转。
(c)此外,有必要回味一下adr伪指令,U-boot中那段relocate代码就是通过adr实
现当前程序是在RAM中还是flash中:
relocate: /* 把U-Boot
重新定位到RAM*/
adr r0, _start /* r0是代码的当
前位置 */
/* adr伪指令,汇编器自动通过当前PC的值算出这条指令中“_start"的值,执行到_
start时PC的值放到r0中:
当此段在flash中执行时r0 = _start = 0;当此段在RAM中执行时_start = _TEXT_B
ASE(在board/smdk2410/con