一、分段式uboot的生成过程解析
1.0 与以往Uboot不同的
两段式的Uboot:直接编译的Uboot不能用,还得经过一次编译生成Uboot-z才行,还要进行二次制作;也就是,先编译生成一个Gzip工具,再结合那个excel表格生成一个.reg文件,最终生成最终文件;现在很多平台,比如全志,也都会采用这种两段式的Uboot的方式。
1.1 顺着顶层Makefile的u-boot-z目标去找
- 首先在顶层的Makefile里面找到u-boot-z
依赖于uboot目录下的u-boot.bin文件
由u-boot.bin叠加reg文件生成u-boot-z.bin
- 分析如何由u-boot.bin生成u-boot-z.bin
其实就是进入到下面这个目录去执行下面这个目录的Makefile,并且是执行默认目标
- 分析以上Makefile
找到要执行生成的目标文件.bin
找到目标文件.bin的依赖:.tmp,.regfile
.regfile:看名字就知道是生成的.reg文件,下面就是判断Uboot顶层文件夹有没有reg文件,或reg文件有没有错误
.tmp:依赖于tmp文件
tmp这个依赖文件又依赖于u-boot.elf
u-boot.elf有依赖于image_data.gzip
image_data.gzip又依赖于BINIMAGE,这个BINIMAGE就是上级传过来的u-boot.bin
SRC, START, COBJS
SRC,来自于SSRC
SSRC
一定是先解压到老版本的U-Boot到DDR里面去,再执行老版本的U-Boot,所以以下部分的源码是不能压缩的
所以分析到这里就知道:elf的依赖里面:
第一个依赖就是:压缩之后的老版本的Uboot
后面二个就是:没有压缩的那一部分
后面2个:START,COBJS
这里面也都是一些与解压相关的,只是语法的问题,并不是重复了
.tmp:由上述uboot.elf生成了.tmp文件
uboot.bin:由 .tmp文件 + regfile一起生成uboot.bin文件
1.2 中间的生成过程,其实是可以去分析的
1.2.1 elf文件时怎么来的
调用链接器的代码
-Bstatic:表示静态链接
-T u-boot.lds:表示指定链接脚本
链接的规则就是: u-boot.lds
链接脚本的路径如下图所示:
从链接脚本中可以看出:ENTRY(_ start)
链接的时候:start.o也是在最前面的,所以会把Start.S放在最前面
-Ttext:指定我们的目标地址,这就是程序的链接地址,这个链接地址是:$(TEXTBASE),即为:
TEXTBASE这个地址,就是我们整个系统的DDR的地址
$(START),$(COBJS):就是一些依赖文件
$(BOOT).map:生成一个map文件,就是用于查符号表之类的
$(OBJDUMP),:生成了一个反汇编文件,如果符号表要查阅反汇编文件,查阅这里就行了
1.2.2 image_data.gzip是压缩包,既然是压缩包的话,那是怎样链接的
其实很简单,就是往压缩包里面塞文件
具体看链接的规则: u-boot.lds
这些都是来源于Source里面的那些东西,并且全部是.o
整个没有被压缩的这段代码,长度必须小于0x6000,也就是必须小于24K Byte
也就是Uboot启动的第一阶段的代码,不能大于24K Byte
系统在启动的时候,会自动从eMMC读取一段固定大小的内容到内部sRAM中,然后跳转去执行它,这部分的内容就是U-Boot的第一阶段,也就是上面列出来的内容,这里面的函数,在第一阶段,会被加载进去;在海思里面,这段sRAM的大小就是24K Byte
就在下面这一部分,往压缩包里面添加东西的了
压缩完成之后,它的属性就设置为.image了,这个是看段属性的
整个步骤完成了之后,就会生成.elf
1.2.3 .tmp文件是如何生成的呢
这个从.elf到.tmp的过程就和以前从.elf到bin的过程差不多
这个从.elf到.tmp的的过程:执行的是OBJCOPY
1.2.4 由.tmp以及regfile文件生成bin文件
tmp就已经是二进制文件了,其实就已经是镜像了
具体如何添加上regfile呢?
首先来分析前三行
第一行:从tmp里面读取前64个字节到tmp1中
第二行:从regfile里面读取8192个字节(其实就是8K)到tmp2中(.reg文件本来是没有8K Byte的,但是在这里,被填充到8K Byte了);这样做是因为:想把reg文件固定一个范围,不想把它设定为一个动态的大小。
第三行:从tmp文件拷贝到输出文件,输出文件跳过前8256字节,生成tmp3
所以:
tmp1就是:tmp的前64个字节;就是一些符号位,相当于一些头部。
tmp2就是:.reg文件被吹大到8192字节(8K Byte);就是寄存器配置的主体。
tmp3就是:tmp文件拷贝到输出文件,输出文件跳过前8256字节,生成tmp3;tmp3文件大小就是tmp文件的大小 + 8256字节;就是:未压缩的Uboot的第一阶段 + 原始Uboot的压缩版。
后面:
把tmp1,tmp2,tmp3合并在一起,就申城额Uboot-z.bin文件
最后的bin文件,其实就是tmp1+tmp2+tmp3,分为3段,这个就是最终的uboot.bin了
可以发现,为什么要腾出8256字节,是因为:8192+64=8256,为了方便放置前面的2个文件
镜像大小:64+8192+temp3大小 = 8256+temp3大小
1.3 分析过程的关键记录
- image_data.gzip:其实就是第一次编译出来的老版本u-boot.bin进过gzip压缩后的压缩文件
分析:以前老版本的U-boot是编译完就直接丢进去运行了,这里呢,还进行了压缩,可以解释的一个原因就是U-boot太大了
- 分析:uboot.bin被压缩肯定带来2个问题:
1.uboot执行时肯定要解压缩再执行
2.最终烧录到emmc中去执行的uboot,肯定有一段是未经过压缩的;肯定有一段解压代码在外部,没有进行压缩。
最终版本的uboot是链接到0x80700000地址的
所以将来最终版本的U-boot一定要被加载到这个地址去运行,否则就会出现运行地址和链接地址不正确,导致运行不了
uboot.elf的内容:前面都是未经压缩的uboot第一阶段,后面是被压缩的原版uboot镜像
前面:eMMC直接Load 24K的文件
后面:后面是因为第二阶段才会被拉过来用
所以:
tmp1就是:tmp的前64个字节;就是一些符号位,相当于一些头部。
tmp2就是:.reg文件被吹大到8192字节(8K Byte);就是寄存器配置的主体。
tmp3就是:tmp文件拷贝到输出文件,输出文件跳过前8256字节,生成tmp3;tmp3文件大小就是tmp文件的大小 + 上8256字节;就是:未压缩的Uboot的第一阶段 + 原始Uboot的压缩版。后面:
把tmp1,tmp2,tmp3合并在一起,就申城额Uboot-z.bin文件
最后的bin文件,其实就是tmp1+tmp2+tmp3,分为3段,这个就是最终的uboot.bin了
可以发现,为什么要腾出8256字节,是因为:8192+64=8256,为了方便放置前面的2个文件
镜像大小:64+8192+temp3大小 = 8256+temp3大小