uboot的lowlevel_init.s解析
2013-10-09 00:11
330 查看
boot版本为201103rc1.
看了一下lowlevel_init.s里面的代码,发现最难懂的地方当属这里了:
第一条语句是获取SMRDATA的地址,SMRDATA的定义在此文件的末尾。第二条语句是获取_TEXT_BASE的值,在start.s中,这个值被定义为CONFIG_SYS_TEXT_BASE。而CONFIG_SYS_TEXT_BASE在目标板目录的config.mk中定义,然后在根目录的config.mk中的以下语句中被包含进来。
然后查看u-boot.lds文件,就知道整个u-boot最后都被编译到CONFIG_SYS_TEXT_BASE这个地址之后,包括代码段、数据段等内容。所以SMRDATA也必定是在这个地址之后。而第三句话就是计算SMRDATA相对于CONFIG_SYS_TEXT_BASE的偏移量。接下来的两句就是把控制寄存器的地址赋给r1,将SMRDATA的结束地址赋给r2。
计算好地址之后,后面的代码是一个循环,按照预先的设计设定每个BANK的属性。
刚开始看这个代码的时候不理解为什么要计算偏移量,后来在网上查了一些资料才逐渐明白。这个涉及到芯片的启动过程。现以上面的SDRDATA为例进行说明。
首先使用objdump –d lowlevel_init.o进行反汇编,查看这一部分代码被预编译为以下内容。
可知SMRDATA的地址就是当前PC值偏移32,在实际运行的时候就是lowlevel的入口地址加32。
再在根目录下使用objdump –d u-boot就可以查到最终的生成文件中lowlevel_init的入口地址了,由于在链接的时候指定了代码段的首地址为0x33f80000,所以lowlevel的入口地址是代码段的首址加上一个偏移量,这样就可以算出SMRDATA的地址就是0x33f80000+lowlevel_init入口的偏移量+SMRDATA本身的段内偏移量。查看uboot根目录底下的System.map文件可知lowlevel_init的地址是0x33f80bf0,SMRDATA的地址是0x33f80c1c。
-----------------------------------------------------------------
在研究lowlevel_init.s这个文件的时候,发现被编译到4K以外的地址上了,结果导致芯片上电的时候程序一跳到这里就跑飞了,后来在网上找资料,发现可以修改LD的链接顺序,保证NAND FLASH上前4K的内容是我们想要的。
要修改LD的选项就要研究Makefile的内容了。先查看lowlevel_init.s所在目录的Makefile,知道其被编译进libfl2440.o中了。然后再查看uboot根目录底下的Makefile,知道LIBBOARD的值就是libfl2440.o,又有以下语句
所以我修改u-boot.lds,在start.o的下面按照其格式强制加上libfl2440.o。
修改完成后重新编译,查看System.map文件,发现lowlevel_init这个函数的入口地址变为0x33f80bf0,而SMRDATA的地址变为0x33f80c1c了,说明修改成功。
弄清楚了这些地址之后再回到开头的问题,arm9在上电的时候如果硬件跳线选择的是从NAND FLASH启动的话,会将NAND FLASH开头的4K内容拷贝到一个叫“stepping stone”的空间中,其首地址是0x0。假设执行到了lowlevel_init里面,还是按照原来的地址去寻找SMRDATA的话,那肯定就找不到了,因为这个时候的代码是运行在0x0~0x00001000这个地址内的,应该去找0x00000c1c这个地址才是正确的。
uboot无法识别部分命令的解决办法
终于弄好uboot从NandFlash启动的部分了,烧进板子的NandFlash中,然后打开串口,上电。出现uboot的启动提示了,这个时候输入saveenv,居然提示说unknow command,顿时有五雷轰顶的感觉,无赖之中尝试了一下其他的命令,发现有些命令可以使用,有些还是提示unknow command。于是查看了一整天的源代码,除了把命令系统的代码搞清楚了以外,这个问题还是没有解决。
由于第一次玩uboot,所以抱着学习的态度就把命令都敲了一遍,心情也郁闷至极。可是在敲入“nand bad”的时候观察输出,发现0x00020000是坏块。掐指一算,MyGod!我的uboot大概是140多K,而查看u-boot.lds可以知道这最后面就是存放命令段和数据段得地方,看来有可能是nand flash的坏块导致我的命令无法正确读取,顿时兴奋不已,赶紧修改链接文件,绕过这一段,看有没有效果。于是将u-boot.lds中__u_boot_cmd_start的值修改为0x33fa3600,虽然这样修改还是会有部分内容在坏块内,但是我是想先验证这是否是问题产生的原因。因为我把命令的地址挪动一下,如果是这里的问题,那产生的结果就有可能是以前能识别的命令,现在不能识别,而以前不能识别的命令,现在能识别了。编译完成之后查看System.map,看到__u_boot_cmd_start的值由0x33fa334c变成了我所修改的值。然后烧进开发板再试,发现测试结果跟以前完全一样,说明不是这里的问题。
于是回过头来看代码,从main_loop->run_command->find_cmd一路打消息打下来,发现此错误是无法匹配“saveenv”字符串导致的,可是明明用U_BOOT_CMD这个宏设置了saveenv命令了啊。用代码打印saveenv命令的name字段,无法得到“saveenv”这个字符串,可是能正常使用的命令都能得到正确的字符串。用UEdit打开u-boot.bin文件以及u-boot.lds可以看到,“saveenv”这个字符串存放到了rodata段,而存放该字符串的地址刚好就是在坏块中。现在问题就弄清楚了,在输入命令之后,程序从__u_boot_cmd_start取出存放命令名的地址,然后去该地址取出命令名,与当前输入的命令作比较,然后再调用相应的处理流程。但是存放命令名字符串的那一部分是坏块,就不能正确进行命令名匹配了。所以只要不把rodata区挪动一下,让程序能正确读取就可以解决问题了。于是将u-boot.lds文件中的rodata区挪到00x33fa8000的地方就好了。
其实按我的理解,由于nand flash的block1都是坏的,所以从128k到256k的部分都不应该使用,像我上面那样改动地址也还是存在风险,有可能其他的数据所存储的区域是坏的,那样也会产生问题。不过已经在程序里面设置uboot的大小为256k,要把128k~256k的地方全部空出来的话,比较麻烦。而且好像我的block1只是有很小一段是坏的,改block的其他page都是好的。所以先这样改着吧。
我用的是飞凌的FL2440开发板,不知道别人的nand flash有多少坏块,好像超过10%就不能用了。但是我的貌似有几百个坏块,总共才2048个blocks,情何以堪啊。不过也真的是感谢飞凌卖的这么“好”的板子,让我把相关部分的知识都好好学习了一遍,希望后面的学习不要再出类似的问题。毕竟我一个新手,什么都不会,真的是伤不起啊!
看了一下lowlevel_init.s里面的代码,发现最难懂的地方当属这里了:
ldr r0, =SMRDATA ldr r1, _TEXT_BASE sub r0, r0, r1 ldr r1, =BWSCON /* Bus Width Status Controller */ add r2, r0, #13*4
第一条语句是获取SMRDATA的地址,SMRDATA的定义在此文件的末尾。第二条语句是获取_TEXT_BASE的值,在start.s中,这个值被定义为CONFIG_SYS_TEXT_BASE。而CONFIG_SYS_TEXT_BASE在目标板目录的config.mk中定义,然后在根目录的config.mk中的以下语句中被包含进来。
LDFLAGS_u-boot += -Bstatic -T $(obj)u-boot.lds $(PLATFORM_LDFLAGS) ifneq ($(CONFIG_SYS_TEXT_BASE),) LDFLAGS_u-boot += -Ttext $(CONFIG_SYS_TEXT_BASE) endif
然后查看u-boot.lds文件,就知道整个u-boot最后都被编译到CONFIG_SYS_TEXT_BASE这个地址之后,包括代码段、数据段等内容。所以SMRDATA也必定是在这个地址之后。而第三句话就是计算SMRDATA相对于CONFIG_SYS_TEXT_BASE的偏移量。接下来的两句就是把控制寄存器的地址赋给r1,将SMRDATA的结束地址赋给r2。
计算好地址之后,后面的代码是一个循环,按照预先的设计设定每个BANK的属性。
刚开始看这个代码的时候不理解为什么要计算偏移量,后来在网上查了一些资料才逐渐明白。这个涉及到芯片的启动过程。现以上面的SDRDATA为例进行说明。
首先使用objdump –d lowlevel_init.o进行反汇编,查看这一部分代码被预编译为以下内容。
lowlevel_init.o: file format elf32-littlearm Disassembly of section .text: 00000000 <_TEXT_BASE>: 0: 33f80000 .word 0x33f80000 00000004 : 4: e59f0020 ldr r0, [pc, #32] ; 2c 8: e51f1010 ldr r1, [pc, #-16] ; 0 <_TEXT_BASE> c: e0400001 sub r0, r0, r1 10: e3a01312 mov r1, #1207959552 ; 0x48000000 14: e2802034 add r2, r0, #52 ; 0x34 18: e4903004 ldr r3, [r0], #4 1c: e4813004 str r3, [r1], #4 20: e1520000 cmp r2, r0 24: 1afffffb bne 18 28: e1a0f00e mov pc, lr 2c: 00000030 .word 0x00000030 00000030 : 30: 2211d120 .word 0x2211d120 34: 00000700 .word 0x00000700 38: 00000700 .word 0x00000700 3c: 00000700 .word 0x00000700 40: 00001f4c .word 0x00001f4c 44: 00000700 .word 0x00000700 48: 00000700 .word 0x00000700 4c: 00018005 .word 0x00018005 50: 00018005 .word 0x00018005 54: 008e0459 .word 0x008e0459 58: 00000032 .word 0x00000032 5c: 00000030 .word 0x00000030 60: 00000030 .word 0x00000030
可知SMRDATA的地址就是当前PC值偏移32,在实际运行的时候就是lowlevel的入口地址加32。
再在根目录下使用objdump –d u-boot就可以查到最终的生成文件中lowlevel_init的入口地址了,由于在链接的时候指定了代码段的首地址为0x33f80000,所以lowlevel的入口地址是代码段的首址加上一个偏移量,这样就可以算出SMRDATA的地址就是0x33f80000+lowlevel_init入口的偏移量+SMRDATA本身的段内偏移量。查看uboot根目录底下的System.map文件可知lowlevel_init的地址是0x33f80bf0,SMRDATA的地址是0x33f80c1c。
-----------------------------------------------------------------
在研究lowlevel_init.s这个文件的时候,发现被编译到4K以外的地址上了,结果导致芯片上电的时候程序一跳到这里就跑飞了,后来在网上找资料,发现可以修改LD的链接顺序,保证NAND FLASH上前4K的内容是我们想要的。
要修改LD的选项就要研究Makefile的内容了。先查看lowlevel_init.s所在目录的Makefile,知道其被编译进libfl2440.o中了。然后再查看uboot根目录底下的Makefile,知道LIBBOARD的值就是libfl2440.o,又有以下语句
$(obj)u-boot : depend / $(SUBDIR) $(OBJS) $(LIBBOARD) $(LIBS) $(LIBSCRIPT) $(obj) u-boot.lds
所以我修改u-boot.lds,在start.o的下面按照其格式强制加上libfl2440.o。
修改完成后重新编译,查看System.map文件,发现lowlevel_init这个函数的入口地址变为0x33f80bf0,而SMRDATA的地址变为0x33f80c1c了,说明修改成功。
弄清楚了这些地址之后再回到开头的问题,arm9在上电的时候如果硬件跳线选择的是从NAND FLASH启动的话,会将NAND FLASH开头的4K内容拷贝到一个叫“stepping stone”的空间中,其首地址是0x0。假设执行到了lowlevel_init里面,还是按照原来的地址去寻找SMRDATA的话,那肯定就找不到了,因为这个时候的代码是运行在0x0~0x00001000这个地址内的,应该去找0x00000c1c这个地址才是正确的。
uboot无法识别部分命令的解决办法
终于弄好uboot从NandFlash启动的部分了,烧进板子的NandFlash中,然后打开串口,上电。出现uboot的启动提示了,这个时候输入saveenv,居然提示说unknow command,顿时有五雷轰顶的感觉,无赖之中尝试了一下其他的命令,发现有些命令可以使用,有些还是提示unknow command。于是查看了一整天的源代码,除了把命令系统的代码搞清楚了以外,这个问题还是没有解决。由于第一次玩uboot,所以抱着学习的态度就把命令都敲了一遍,心情也郁闷至极。可是在敲入“nand bad”的时候观察输出,发现0x00020000是坏块。掐指一算,MyGod!我的uboot大概是140多K,而查看u-boot.lds可以知道这最后面就是存放命令段和数据段得地方,看来有可能是nand flash的坏块导致我的命令无法正确读取,顿时兴奋不已,赶紧修改链接文件,绕过这一段,看有没有效果。于是将u-boot.lds中__u_boot_cmd_start的值修改为0x33fa3600,虽然这样修改还是会有部分内容在坏块内,但是我是想先验证这是否是问题产生的原因。因为我把命令的地址挪动一下,如果是这里的问题,那产生的结果就有可能是以前能识别的命令,现在不能识别,而以前不能识别的命令,现在能识别了。编译完成之后查看System.map,看到__u_boot_cmd_start的值由0x33fa334c变成了我所修改的值。然后烧进开发板再试,发现测试结果跟以前完全一样,说明不是这里的问题。
于是回过头来看代码,从main_loop->run_command->find_cmd一路打消息打下来,发现此错误是无法匹配“saveenv”字符串导致的,可是明明用U_BOOT_CMD这个宏设置了saveenv命令了啊。用代码打印saveenv命令的name字段,无法得到“saveenv”这个字符串,可是能正常使用的命令都能得到正确的字符串。用UEdit打开u-boot.bin文件以及u-boot.lds可以看到,“saveenv”这个字符串存放到了rodata段,而存放该字符串的地址刚好就是在坏块中。现在问题就弄清楚了,在输入命令之后,程序从__u_boot_cmd_start取出存放命令名的地址,然后去该地址取出命令名,与当前输入的命令作比较,然后再调用相应的处理流程。但是存放命令名字符串的那一部分是坏块,就不能正确进行命令名匹配了。所以只要不把rodata区挪动一下,让程序能正确读取就可以解决问题了。于是将u-boot.lds文件中的rodata区挪到00x33fa8000的地方就好了。
其实按我的理解,由于nand flash的block1都是坏的,所以从128k到256k的部分都不应该使用,像我上面那样改动地址也还是存在风险,有可能其他的数据所存储的区域是坏的,那样也会产生问题。不过已经在程序里面设置uboot的大小为256k,要把128k~256k的地方全部空出来的话,比较麻烦。而且好像我的block1只是有很小一段是坏的,改block的其他page都是好的。所以先这样改着吧。
我用的是飞凌的FL2440开发板,不知道别人的nand flash有多少坏块,好像超过10%就不能用了。但是我的貌似有几百个坏块,总共才2048个blocks,情何以堪啊。不过也真的是感谢飞凌卖的这么“好”的板子,让我把相关部分的知识都好好学习了一遍,希望后面的学习不要再出类似的问题。毕竟我一个新手,什么都不会,真的是伤不起啊!
相关文章推荐
- uboot的lowlevel_init.s解析
- uboot的lowlevel_init.s解析
- 6410板uboot的lowlevel_init.S
- uboot的lowlevel_init.s解读
- uboot代码详解——lowlevel.S
- start.s之lowlevel_init分析
- U-boot-2009.03移植之九:第一阶段之lowlevel_init.S的理解和修改
- Android的init过程:初始化语言(init.rc)解析
- Android的init过程(二):初始化语言(init.rc)解析
- Android init.rc脚本解析
- error LNK2019: 无法解析的外部符号 _mysql_init@4,该符号在函数 "public: void
- 史陶比尔机器人的 LLI (Low Level Interface)
- uboot下init_sequence_f函数之jump_to_copy
- error LNK2019: 无法解析的外部符号 _Direct3DCreate9@4,该符号在函数 "int __cdecl InitD3D(struct HWND__ *,unsigned lo
- uboot下init_sequence_f函数之setup_board_extra
- tdp_page_fault 函数解析之level,gfn变量的含义
- uboot下init_sequence_f函数之post_init_f
- linux内核驱动 之 module_init解析 (上)
- VS中MFC连接MySQL由于系统不同位(32/64)引起的错误:无法解析的外部符号 _mysql_init@4,_mysql_query,_mysql_error
- Android init.rc文件解析过程详解(三)