[源码分析] Helper2416-21——U-boot学习笔记00——make smdk2416_config/make过程分析

yuanlai2010   2014-7-27 18:49 楼主
make smdk2416_config/make过程分析
参与Helper2416开发板助学计划心得
参考HELPER2416_V2 开发板 LINUX 用户手册,知道可以通过
make smdk2416_config
make
这两条命令编译生成我们所需的u-boot.bin文件,第一条命令make smdk2416_config主要是完成一些配置工作的,那么这条命令具体完成了哪些配置工作呢?
以下参考《嵌入式Linux应用开发完全手册》对这两条命令做一些分析:
首先通过make smdk2416_config 完成配置
由于上面是从u-boot更目录下make的,所以找到u-boot更目录下的makefile文件,在文件中搜索关键字“smdk2416_config”定位到以下代码
uboot.0.0.png
再继续找到MKCONFIG的原形
ubbot.0.2.png
由于是在个根目录下便编译的,则MKCONFIG就是根目录下的mkconfig文件,实际上就是一个脚本文件。那么当我们执行make smdk2416_config这条命令的时候,实际执行的就是下面这条命令:
./mkconfig smdk2416 arm s3c24xx smdk2416 samsuny s3c2416
$0 $1 $2 $3 $4 $5 $6
($0~$6是脚本的参数 ,先对应写出来,等下方便阅读。)
打开u-boot根目录下的mkconfig脚本文件,在第六行可以看到他的使用方法:
ubbot.0.3.png
接着看看mkconfig这个脚本完成的工作。
1:确定开发板名称BOARD_NAME
uboot.1.0.png
while循环由于条件不成立,什么事都没干。执行到23行就有BOARD_NAME = smdk2416了,
2:创建到平台/开发板相关的头文件链接
uboot.1.1.png
由于33行的条件并不满足,所以直接执行else分支的代码:先进入到include目录下,然后删除asm文件,最后把再次建立asm并链接到 asm-arm目录。
接着
uboot.1.2.png
先删除asm-arm/arch目录,由于$6 =s3c2416,所以执行else分支,并且LNPREFIX为空,所以56行实际执行的就是“ln –s arch-s3c2416 asm-arm/arch”.
然后$3 = s3c24xx成立,执行这段代码
uboot.1.3.png
删除inlude目录下的regs.h文件,重新建立regs.h文件并链接到s3c2416.h文件,然后蛋疼了,又执行了一遍 rm –f asm-arm/arch…
继续往下看
uboot.1.6.png
条件成立,重新建立asm-arm/proc文件,并让它链接到proc-armv目录。
3:创建顶层Makefile包含的文件include/config.mk
uboot.1.4.png
很显然,创建的config.mk文件内容如下
ARCH = arm
CPU = s3c24xx
BOARD = smdk2416
VENDOR = samsuny
SOC = s3c2416
4:创建开发板相关头文件include/config.h
uboot.1.5.png
APPEND维持原值“no”,所以config.h被重新建立,它的内容如下:
/*Automatically generated - do not edit */
#include
从这里可以看出,如果要在board目录下新建一个开发板的目录,则在include/configs目录下也要建立一个文件.h,里面存放的就是开发板的配置信息
到这里make smdk2416_config的工作就全部完成了,总结一下就是完成了一下四项工作:
1:确定开发板名称BOARD_NAME
2:创建到平台/开发板相关的头文件链接
3:创建顶层Makefile包含的文件include/config.mk
4:创建开发板相关头文件include/config.h
接下来就是通过make 或者 make all 编译了
配置完后,执行”make all ”即可编译,还是从顶层Makefile文件开始分析。
首先
uboot.2.0.png
条件成立,包含了由上配置过程生成的include/config.mk文件,获得ARCH CPU BOARD VENDORSOC的信息,这几个值依次为arm s3c24xx smdk2416 samsuny s3c2416
uboot.2.1.png
uboot.2.2.png
接着根据上面ARCH变量的值确定编译器,之后包含顶层目录下的config.mk文件,通过上面5个变量的值进一步确定编译选项等。
顶层目录下config.mk文件部分内容如下所示
uboot.2.3.png
uboot.2.4.png
uboot.2.5.png
其中BOARDDIR 、LDFLAGS的值在接下来的Makefile分析中很重要。
在board/samsuny/smdk2416/config.mk中定义了” TEXT_BASE = 0xc3e00000”,那么具体的有:
BOARDDIR= samsuny/smdk2416
LDFLAGS中有“-T board/samsuny/smdk2416/u-boot.lds –Ttext0xc3e00000”。
继续来看Makefile文件
uboot.2.6.png
从187行得知,OBJS的第一个值为“cpu/$(CPU)/start.o”,即”cpu/s3c24xx/start.o”
接下来从201行开始指定了LIBS变量就平台/开发板相关的各个目录、通用目录下的库。
OBJS、LIBS所代表的.o、.a文件就是u-boot的构成,它们通过如下的命令由相应的源文件编译得到。
uboot.2.7.png
生成所有的.o、.a文件之后剩下的就是最后的连接了,对应了Makefile文件中的如下几行:
uboot.2.8.png
uboot.2.9.png
先由第320~325的规则得到elf格式的u-boot文件,最后转换为二进制文件格式u-boot.bin文件等。其中在根目录写的config.mk文件中定义的LDFLAGS确定了连接方式,其中的“-Tboard/samsuny/smdk2416/u-boot.lds –Ttext 0xc3e00000”指定了程序的布局、地址。
如下u-boot.lds的内容所示:
uboot.3.0.png
从上图可以知道 cpu/s3c24xx/start.o 被放在程序的最前面,所以整个u-boot的入口就在cpu/s3c24xx/start.o中,这样接下来u-boot的流程分析就可以从start.s 开始了。
最后总结下u-boot的编译流程。
1:首先编译cpu/$(CPU)/start.S
2:然后,对于平台/开发板相关的每个目录、每个通用目录都使用他们各自的Makefile生成相应的库、
3:将1、2步生成的.o、.a文件按照board/$(BOARDDIR)/config.mk文件中指定的代码段起始地址、board/$(BOARDDIR)/u-boot.lds连接进行连接。
4:第3步得到的是ELF格式的u-boot,后面Makefile还会将它转换为二进制格式。
下一步试着去分析u-boot源码!
论坛ID:yuanlai2010
发表时间:2014-07-27
本帖最后由 yuanlai2010 于 2014-7-27 19:00 编辑

回复评论 (10)

这样的分析很细致,只是对于初学者来说,难了点,建议自上而下,先从应用着手,当然,从下到上的方法基础可能会扎实一些,适合没有项目压力又有耐心的少部分人。。。
My dreams will go on... http://www.jyxtec.com
点赞  2014-7-28 09:30
引用: spacexplorer 发表于 2014-7-28 09:30
这样的分析很细致,只是对于初学者来说,难了点,建议自上而下,先从应用着手,当然,从下到上的方法基础可 ...

我主要是觉得自己刚玩过一段时间的裸机编程,去分析uboot刚好只是一个深入,现在主要想分析下内核的启动参数及实现方式,看能不能让自己的YL-boot启动内核。对于应用,由于没有C++的功底确实也不好去学习QT,所以现在只能边学点C'++的东西,边用C做一些底层的分析
点赞  2014-7-28 09:55
引用: yuanlai2010 发表于 2014-7-28 09:55
我主要是觉得自己刚玩过一段时间的裸机编程,去分析uboot刚好只是一个深入,现在主要想分析下内核的启动 ...

用你的YL_BOOT是可以启动内核的,只是传启动参数的时候是放到内核编译启始地址之前的8K,最好分析一下uboot里的bootm命令。
My dreams will go on... http://www.jyxtec.com
点赞  2014-7-28 10:44
引用: spacexplorer 发表于 2014-7-28 10:44
用你的YL_BOOT是可以启动内核的,只是传启动参数的时候是放到内核编译启始地址之前的8K,最好分析一下ubo ...

BOSS您好!我刚看了下uboot启动内核的那一段代码,有以下几个疑问!

我看了下源码这个参数的地址是通过寄存器R2的值传递到内核入口函数的,理论上这个值可以是任意的,为什么一定要在启动地址的之前的8K呢?
在启动过程中通过串口打印的信息可以知道,内核是被加载到0x30008000的物理地址,而TAG却位于0x30000100的位置,也不在8K之内。

另外BOSS为什么要把SDRAM的地址重映射到0xc0000000的地方,这样做有什么好处呢?
在跳转到kernel入口之前有没有关闭mmu呢?
还有在跳转到内核入口之前必须要关闭mmu吗?
点赞  2014-7-28 18:30
1、内核执行地址是0x30008000,参数在其前边的一段区域,我不记得是4K还是8K了,只知道是其前边的区域
2、重映射到0xC0000000应该是none cache的,就是不写缓冲,保证每次操作都会写到内存
3、跳到内核手,会关闭再重新配置MMU,因为内核不知道UBOOT是怎么配置的。
4、是不是必须的,我就不知道了。。。
My dreams will go on... http://www.jyxtec.com
点赞  2014-7-28 19:18
引用: spacexplorer 发表于 2014-7-28 19:18
1、内核执行地址是0x30008000,参数在其前边的一段区域,我不记得是4K还是8K了,只知道是其前边的区域
2、 ...

BOSS..我想问下UBOOT把uboot、kernel、rootfs写进NAND的时候,是不是没有把ECC校验值写进去?
点赞  2014-7-29 19:14
引用: yuanlai2010 发表于 2014-7-29 19:14
BOSS..我想问下UBOOT把uboot、kernel、rootfs写进NAND的时候,是不是没有把ECC校验值写进去?

在UBOOT里,用nand write写入uboot和kernel的时候,会自动加入ecc数据,在写rootfs的时候会按照镜像的内容还写入oob数据。
My dreams will go on... http://www.jyxtec.com
点赞  2014-7-29 22:07
引用: spacexplorer 发表于 2014-7-29 22:07
在UBOOT里,用nand write写入uboot和kernel的时候,会自动加入ecc数据,在写rootfs的时候会按照镜像的内 ...

但是我不知道是什么原因,我用自己的nand读函数从nand0x40000处读出来的内容都是0,如果使用自己的nand写函数写进去,读出来又是正确的!
点赞  2014-7-29 22:22
写的比较详细了,顶一下楼主
点赞  2014-9-29 14:08
赞一个  等用到的时候在来学习
点赞  2016-6-22 11:19
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复