移植u-boot-2015.07之修改程序支持NAND Flash
1.为什么要支持NAND Flash启动
由于NAND Flash 的存储空间大并且价格便宜(相对于 NOR Flash 来说),所以程序的存储位置一般会放在 NAND FLash 里面,虽然 NAND Flash 也有缺点,那就是容易发生位反转,但是这并不妨碍 NAND Flash 的优势,所以从 NAND Flash 启动是非常有必要的。还有一个问题就是在 S3C2440 上电的时候,只会从 NAND Flash 的前面4K空间拷贝代码到内存空间里面,这就导致了一些比较大的bootloader不能够直接放入内存空间运行,而是由程序从 NAND Flash 里面拷贝到内存空间里面去运行
2.添加驱动函数
添加nand的读函数,添加bss段的清零函数到单板目录下面(建立init.c文件,并且添加到单板目录下的 makefile 文件中去)。这个代码需要自己去实现,这里不再赘述。
3.修改设置
注释掉 arch/arm/config.mk 里面的82行
LDFLAGS_u-boot += -pie
(我们使用自己的重定位函数,为了能够从 nand flash 启动)修改smdk2440.h里面的
CONFIG_SYS_TEXT_BASE
为 0x33f00000,这个就是代码的链接地址把最开始要执行的代码都放在bin文件的最前面,以防被编译器编译到4K空间之外,在 arch/arm/cpu/u-boot.lds 里面修改,包括
arch/arm/lib/built-in.o board/samsung/smdk2440/built-in.o。本版本u-boot将一个文件夹下面的c文件都链接成一个.o文件,名字为built-in.o,所以我们直接写上built-in.o即可。要想将一个单独的文件放出来以供手动指定链接位置的话,把该文件所在目录下面的 Makefile 文件中该文件对应的obj-y选项改为 extra-y 即可,这样的话就可以在u-boot.lds里面单独指定一个c文件的位置,这点查看start.S文件所在文件夹下面的Makefile就可以知道。另外把开头的#include <config.h>
给注释掉,不然当你使用双斜杠注释掉板级文件头文件中的一些宏定义的时候make会出现错误,主要就是根目录下的 u-boot.lds 文件头部会出现一大堆注释宏定义,当然,出现错误的时候直接在生成的 u-boot.lds 文件里面删除也是可以的,这里为了方便就把它给注释掉了
. = 0x00000000;
. = ALIGN(4);
.text :
{
*(.__image_copy_start)
*(.vectors)
CPUDIR/start.o (.text*)
arch/arm/lib/crt0.o (.text*)
arch/arm/lib/vectors.o (.text*)
board/samsung/smdk2440/built-in.o (.text*)
*(.text*)
}
4.修改 board_init_f
注意:这里说的board_init_f指的是board.c里面的函数,而不是board_f.c里面的函数
- 在crt0.S里面进行代码的重定位,在board_init_f上面添加一个标识符,例如:
bym_board_init_f:
bl board_init_f
/* 然后在上面进行代码的重定位,修改后如下所示 */
ldr r0, =_start
mov r1, #0
ldr r2, =__bss_start
sub r2, r2, r0
bl bym_copy2sdram
bym_board_init_f:
bl board_init_f
- 在board_init_f里面注释掉
addr -= gd->mon_len;
addr &= ~(4096 - 1);
改为
addr = (ulong)&_start; /* 指向代码段的开始,人为指定 */
5.修改重定位代码
在Crt0.S里面注释掉所有与代码重定位和清除bss段有关的代码,用自己的代码替换之,替换后的代码如下:
ldr r0, =__image_copy_start
mov r1, #0
/* 为避免 __image_copy_start 等值错误而加的 */
ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */
ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */
/* 为避免 __image_copy_start 值错误而加的 */
ldr r2, =__image_copy_end
sub r2, r2, r0
bl bym_cpoy2sdram
bl clear_bss
ldr pc, =bym_board_init_f
bym_board_init_f:
/* mov r0, #0 not needed due to above code */
ldr r0,=0x00000000
bl board_init_f
6.测试
拷贝并覆盖以上修改文件到虚拟机上面
make smdk2440_defconfig
- make 这一步出现u-boot contains unexpected relocations.通过网上查找资料,发现是编译的时候有checkarmreloc选项,再次去arch/arm/config.mk里面修改,注释掉ALL-y += checkarmreloc,重新make。该行代码指的是检测重定位信息,我们把所有的重定位代码信息都给注释掉了(包括前面的编译选项),所以这里会出现错误。
悲剧
下载之后启动不成功,查看反汇编文件,发现__bss_start的值并不是我们期望的在0x33f00000之后的一个值,而是0,这点显然是不对的,而且在make的时候最后链接之后出现了奇怪的错误。这样想来这一版本的u-boot还不单单是通过修改 CONFIG_SYS_TEXT_BASE 就可以达到完全改变程序链接地址的目的,此项搁置暂时转为2012版本的移植,以后再来看这个版本的
转机
我又回来了,上面说到反汇编之后查看__bss_start的值不对,我百无聊赖之下把crt0.S里面的官方重定位代码又加上了,重新编译,__bss_start值变得正常了,下载到单板上面可以运行前面的串口初始化以及打印CPU信息那里。问题何在,我又一次去掉了系统原有重定位代码,再次编译,__bss_start值再次不正常,然后我怀疑是重定位里面代码有什么猫腻,然后一点一点去掉重定位函数里面的代码,我发现如果要是去掉了与u-boot.lds文件里面指定的__rel_dyn_start与__rel_dyn_end标号有关的代码__bss_start的值就会变得不正常。万般无奈之下只得把这两句代码搬移到crt0.S里面自己实现的重定位代码之前如上面的代码,不影响重定位代码的参数值,又使用了这两个标号,终于成功。然后我怀疑是编译器的优化作用或是别的什么地方有特殊的处理,总之非常奇怪,这点暂时搁置,现在已经实现了支持 nand flash 启动的代码了
7.从 board_f.c 里面启动
然后我想从board_f.c里面的board_init_f函数启动,没错我就是这么爱折腾。再次修改smdk2440.h里面,还原 #define CONFIG_SYS_GENERIC_BOARD。更改board_init_f(board_f.c里面的)函数里面调用函数组里面的reserve_uboot函数里面的gd->relocaddr赋值语句
// gd->relocaddr -= gd->mon_len;
// gd->relocaddr &= ~(4096 - 1);
#ifdef CONFIG_E500
/* round down to next 64 kB limit so that IVPR stays aligned */
gd->relocaddr &= ~(65536 - 1);
#endif
gd->relocaddr = (ulong)&__image_copy_start;
保存覆盖文件到虚拟机,重新make并且下载。程序成功运行到等待用户输入命令界面。