HI3516DV300_17_Uboot第二阶段的启动


一、从这里开始

1.1 分析内存空间

这里就主要集中力量,做了一件事情:去解压缩老版本的U-Boot

观察这幅图

上面这张图的黑框部分,就是总共263 KB

这263 KB由3部分组成:

A是第一部分:64字节,就是制作的压缩后的U-Boot的前64字节,就是一些当做头,校验使用的,具体内容取决于Hi_Gzip工具,所以我们无从得知,因为是人家从来做对接的。

B是第二部分:8KB,存放的是寄存器的配置值。

C+D是第三部分:
包含未压缩的部分C,也就是第一阶段运行的代码,这部分的代码小于24KB,所以,C是小于24KB的
包含被压缩的老版本的u-boot.bin,也就是D,也就是第一步编译出来的那个:

到目前为止,C那一部分,也就是未压缩的那一部分,已经从eMMC Load到sRAM中了。映射到DDR中的0x80700000地址中去,之前一直运行的都是C那一部分

到目前为止,D那一部分,也就是被压缩的那一部分,已经从eMMC Load到DDR中了

1.2 start_armboot要解压到的目的地址

  • 首先把串口初始化一下,但是在前面,串口已经初始化过一次了

  • 然后用串口打印了一个字符串,打印的字符串是:“\r\nUncompress”,但是OK还没有看到

  • 使用直接地址模式

  • 初始化硬件解压模块

Hi3516DV300内部有一个硬件模块,专门用来进行压缩和解压缩使用的
硬件的模块,是一个有知识产权的解压模块

  • 这里在准备要解压缩的目标地址

pdst_l32:Pointer Destination of Low 32,这是在DDR中的目标地址。

这个目标地址是:IMAGE_ENTRY

解压的目的地址,与之前之前存放的Uboot-z.bin的地址,有1MB的容量 (这也就是Hi-Tool下载的时候选用1MB的长度的原因之一)

之前烧录的Uboot-z.bin也就在263KB,还不到1MB,因此不会发生踩踏事故

因此,解压后的老版本U-Boot肯定就要从0x8080000开始运行,也就是老版本的U-Boot肯定运行到了0x8080000这个地址

原来链接到0x80700000主要是为了执行C那部分的代码;因为从sRAM加载到DDR的时候,一定需要用到B这一部分,所以也可能那24KB是包含A,B,C的(A不一定包含,B一定包含,C一定包含,并且C一定小于24KB),所以现在修改为如下图所示:

1.3 分析start_armboot源码(解压之前)

  • 分析要解压的长度:

incbin:include bin

这里要include的是一个二进制文件:image_data.lzma
其实也就是这个文件:

其实是把压缩后的老版本的U-Boot放在这里,因为压缩后就是二进制了,就没有格式了,把整个压缩文件include到这里,把起始地址作为input_data,把结束地址作为input_data_end

这样做的目的是:将来方便链接脚本进行重新排布文件

  • 分析Gzip要解析的一些头文件

这里是复制Gzip里面的一些头文件的长度,这里还没开始解压

  • 真正开始调用硬件解压

本来是在DDR的0x80700000,现在解压后放到DDR的0x80800000,0x80800000里面放的就是我们解压缩过的U-Boot了

  • 解压后

U-boot中,A,C,D这一部分已经没用了;
B这一部分可能还有点用,因为后面可能涉及到硬件的操作,凡是涉及到硬件操作的,都会用到寄存器中的.reg文件
E这一部分就是完全有用的

到了E这一部分,其实整个芯片,该初始化的,都已经初始化了

1.3 分析start_armboot源码(解压之后)

首先把硬件解压缩模块给关掉

直接定义了一个函数指针变量

之前都是先定义类型,再用类型定义变量

强制类型转换后的0x80800000赋值给uboot,其实就是把这个地址强制类型转换成一个函数指针,后面再去执行这个函数

把原来的icache给清空,也就是把原来的上下文给清空,准备另一套东西的执行

执行uboot这个函数,其实就是跳转到0x80800000这个地址,就差直接goto这个地址了

1.4 解压之后,跳到u-boot,会首先执行哪行源码呢

1.4.1 首先回忆制作时候的Makefile

1.4.2 0x80800000地址对应的代码在哪里呢

其实就是分析一下老版本的U-boot,看把谁链接到前面了

所以就先分析一下链接脚本

第一个链接脚本就是这个,这个也是第二次制作的时候使用的链接脚本,也就是相当于A,B,C,D这个的链接脚本

那么E这个Uboot的链接脚本在哪里呢

从最顶层的Makefile来推

最后翻阅文件夹得:只有下面这个文件夹中有u-boot.lds

因为是从顶层的Makefile编译得到U-boot的,所以查顶层的Makefile必然能得到链接脚本在什么地方

E这个Uboot的链接脚本在下面这个目录下

来开始分析链接脚本

发现它的ENTRY还是_start,他在运行的时候,还是从_start开始的,那么到底是哪一个_start呢?肯定不是最早分析的那个_start了,所以这个体系里面有好几个_start.s,到底是哪个_start.s呢,这是一个需要确认的问题

从这个链接脚本往下翻阅,可以查看到

CPUDIR到底是哪一个呢?肯定不是cpu,实际的CPU的话,那么就是armv7,也就是链接脚本目录下的armv7:

所以就是下面这个目录的Start.s,也就是E那一部分的Start.s

但是这个体系下面还有其他的start.s,其实这个就是,A,B,C,D这一部分的Start.s,也就是C那一部分的代码

接下来就分析也就是E那一部分的Start.s

理清这个思路,这个Uboot其实是一个套一个,相当于虎头蛇尾;先执行一个解压,然后执行真正的U-Boot,一夜回到解放前

但是,这个时候的状态是不一样的,比如说:DDR,时钟,这些是好的了,下面跳转到来执行这个Start.s

1.4.3 分析目前这个Start.s

  • 跳转过来立马执行第一行指令,第一行指令就是reset,这里的reset仅仅是一个符号,并不是真正地跳转到系统的0地址

  • save_boot_params

就是一个空的函数,没有具体代码

  • 和虚拟化有关的,啥都没干

  • 关中断相关的

  • 重新定位异常向量表相关的

  • 跳过low_level_init相关的,这个是肯定要跳过的

  • bl _ main,很快就跳转到_main了,没事是什么事都没有做,就跳转到main了,所以不用跳转到Start.s,直接跳转到_ main也是可以的;所以上面这个Start.s其实就是空的,啥也没干。

  • 那么_main是谁呀,其实就是main函数,链接的时候,就是以对等的当时链接了_main

  • main函数在什么地方呢?

main在arch/arm/lib/crt0.s中

crt0.s可能没见过,但是crt0.o一定见过,程序如果在链接的时候,没有main函数,链接的时候,就会报错,说在crt0.o里面找不到main,我们平时写的代码呢,我们工具链的库里面,给我们提供了crt0.o,那是所有程序,所有进程,最开始的那一段。
因为这个属于工具链的一部分,所以就在lib目录下,其实main函数里面做的事情,就是做main之前的C语言运行环境的构建,最后跳转到main函数里面去运行,所以就跳到这里来了。

通过搜索也知道在什么地方

所以这个crt0.s就是main函数

  • 来分析crt0.s

设置C语言运行的初始环境

有一个board)init_f(0),也有一个board_init_r(0)

倒是在 board_init_f这个函数里面干了很多的事情

可以发现,跳转到crt0.s之后,一切的操作都很标准了,然后顺着这个往下走,就可以发现有global data

以及zero_global_data(),类似于清零之类的

global_data 里面的一些初始化

initcall_run_list

这个函数传了个参数,叫:init_sequence_f,里面有一堆函数;这些初始化函数的返回值和接收参数类型都是一样的,所以就定义了一个函数指针数组。

然后就在这个函数里面,挨个去执行它,这里面有一个for循环,挨个进行调用,如果有一个出错了,那么就退出,如果没有一个出错,那么就挨个循环去执行。

后面的流程,基本就和通用的U-boot很类似了,后面就是一边顺着这个流程走,一边顺着这个boot info去看

  • 到现在为止

上面这段U-boot,其实是分段式的U-boot带来的;后面的U-boot启动,其实和传统的U-boot启动就一样了

所以下面来分析这句话的打印信息:

肯定是从这里开始的

再往后

往后有很多是没打印的,因为很多调用的是debug函数在输出,大部分是没有输出的

初始化完成之后,到这里,就进入一个hang了,就挂住了

最后init到这里了

一边分析,一边对着boot的log来看

截止现在,U-boot就分析完了,后面的U-boot和传统的应该差不多,至少有90%是差不多的

不同的是分段式设计,以及它压缩了,压缩了地话,就多了解压缩这样一个流程;但是这个解压呢,又和内核的自解压是比较相似的

1.4.3 未尽事宜

  • Excel表格,里面怎么去设置,这样一些细节

因为默认会给一些选型参考,并且可以直接使用海思他们已经调好的

列表里面不支持的器件,大概率就不好采购;也可能不兼容,不兼容还是要用,那么就要找海思的支持人员了;调这个东西也是比较麻烦的。

下节课讲内核,主要就是讲解驱动


Author: Ruimin Huang
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Ruimin Huang !
  TOC