26. Uboot启动流程分析——上¶
26.1. 前言¶
本章主要讲解CPU上电到Uboot(或裸机)入口的启动流程和各个阶段实现的功能简单分析一下,主要是一些配置相关的寄存器地址与寄存器值,本教程提供给对启动流程好奇的同学学习,初学者仅当了解即可不影响后续的镜像构建。 本章内容也为个人见解,如有不对之处欢迎指出
26.2. 启动流程简介¶
上电 —> 设备初始化 —> 启动设备 —> 镜像头 —> Uboot入口
26.3. 设备初始化¶
26.3.1. 简述¶
这里的功能主要是原厂的固化在芯片内的程序的功能:简单初始化一下总线资源,再通过外部引脚判断从什么类型的flash中读取数据进行外设的初始化
26.3.2. 内存映射¶
首先需要先明确的是imx6ull里是带有ROM和RAM的,我们称它为iROM和iRAM。
iROM作用:存储异常向量表,HAB API向量表,ROM API向量表,日志缓冲区,固化的出厂程序
iRAM作用:运行出厂程序和镜像4K头部数据
小知识:这里的OCRAM Free Area在启动后是可以在Uboot使用的。
26.3.4. 时钟初始化¶
启动的时钟有: ARM,System,USB,AHB,IPG,NAND,UART2,ECSPI1-4,QSPI1,USDHC1-2,NOR,OneNAND
26.3.5. 启动MMU/L2缓存¶
启动ROM包括一个功能,使内存管理单元(MMU)和缓存,以提高启动速度。 在镜像下载开始时,将启用Ll指令缓存。图像认证时需要启用L1数据缓存、L2缓存和MMU。当HAB认证完成时,ROM会关闭L1数据缓存、L2缓存和MMU。其中L1指令缓存、L1数据缓存、L2缓存和MMU由eFuse控制。默认情况下,这些是启用的。
26.3.6. 映射异常向量表¶
该表位于iROM的头部,映射后存于iRAM的0x0091FFB8-0x0091FFFF地址中
26.4. 启动设备¶
26.4.1. 简述¶
这里的功能是根据FUSE识别相应的flash
26.4.2. FLASH选择(FUSE选择)¶
26.4.3. 镜像头读取流程分析¶
本小节主要是讲解各个Flash是如何找到镜像头的
镜像头是指IVT,Boot data,Device configuration data(DCD),往下我们简称镜像头。
26.4.3.1. NOR¶
该flash支持XIP可以在片上运行程序,需要注意的是NOR只能像RAM一样读取数据但不能像RAM一样写入,写入还得像NAND那样擦除再写入,所以其镜像头的加载可以是整个空间
然后根据镜像头配置好时钟和各种外设(内置外设),具体详细的镜像头分析将在后面讲解。
26.4.3.2. OneNAND¶
OneNAND则是从256byte开始读取往后的1K(0页0块的扇区0和扇区1)作为镜像头将其加载到内部的iRAM中,这1K必须包含完整的镜像头数据,但我们常用的NAND和eMMC镜像头(2K大小)是不符合的,所以只需要启动主要的内置外设即可将镜像头压缩到1K内,剩下的功能可以在需要使用时再到外置DDR中配置。
而OneNAND我们不常用,所以后面不会讲解这个仅1K的镜像头数据。
26.4.3.3. Raw NAND¶
Raw NAND即我们常使用的NAND flash也是固态硬盘中的固态颗粒,imx6ull支持MLC/SLC的颗粒,我们出厂的板子是SLC的。
NAND的存储地址较为特殊,不是板子指定,而是由FCB决定。讲到FCB不得不提一下DBBT。
FCB:全称为Firmware configuration block,主要描述了NAND的各项硬件参数,ECC纠正参数和镜像入口
DBBT:全称为Discovered Bad Block Table,主要作用是记录NAND的坏块地址。
FCB和DBBT都具有很多参数以及ECC如何纠错等内容,感兴趣的可以向客服反馈,人多的话我出多一章讲解NAND的详细启动流程。
回归正题NAND是如何找到镜像头的呢?
FCB中有一行参数 Firmware1_startingPage
我们将NAND的头100K数据提取出来看一下
可以看的出,这里给出的值为 00 02
根据大小端可以知道,相应值为0x200,但是这个并不是指在NAND中的地址,而是指页数
还需要一个参数是页大小,页大小可以从NAND数据手册上找到
也可以从uboot的命令界面输入 nand info 查看
1 | nand info
|
还可以根据FCB描述的NAND参数进行计算
则可以算出页大小=0x1000=4096byte
地址=页数*页大小(byte)=0x200(512)*0x1000(4*1024)=0x200000(2097152)
现在有了入口地址,我们去看看0x200000在NAND中存放的是什么
看过4K数据头的同学对这个不会陌生,这个就是我们说的镜像头。
这个emmc版本的uboot头部数据,与NAND的非常像。
这里0x00200000应该是NXP为了和其他flash镜像一样保持预留了0x400(IVT Offset)的一段空白,真正的数据头开始是从0x00200400开始的。
小疑问:为什么这里的mmc的是从0x0开始的呢?
因为这里只是单独的uboot并没有烧录到mmc中,烧写到mmc中也是要空出这一段0x400(IVT Offset)的。
26.4.3.4. SD/MMC/eSD/SDXC/eMMC4.4¶
SD和emmc一类都是根据跳过1K读取4K原则。
这1K里包含了MBR表,主要记录分区信息
既然讲到MBR表,我们就讲讲MMC/SD卡是如何分区的吧。
MBR表中有一块存储DPT的表,DPT中包含了分区信息
这是我SD卡的分区情况,可以在Linux下用fdisk -l查看
红色的为逻辑起始扇区:即第9,10,11,12字节的内容,0x2000=8192
绿色的为扇区数:即第13,14,15,16字节内容,0x14000=81920
蓝色的为结束扇区:逻辑扇区+扇区数-1=90111
黄色的为分区类型:即第5字节内容,如图0e(第二扇区为83),则ID为e(第二扇区为83)
那应该从0x400(1K)往后的地址就是我们要找的镜像头了
也确实如此
26.4.3.5. Quad SPI flash¶
与MMC较为相似,之后补充
26.4.3.6. EEPROM¶
与MMC较为相似,之后补充
26.5. 镜像头分析¶
镜像头的作用主要是,对外置DDR进行初始化,时钟的设置,镜像的大小,uboot(裸机)的入口地址,CPU的电源控制等。具体的功能我已经总结到了如下的图中。
这里我提供一份mmc的uboot,可以在Linux下使用hexduemp进行查看,也可以对照着我提供的图与镜像头图一起看。
可以将本图保持放大观看
26.6. Uboot入口¶
在镜像头中有一个名为entry地址0x87800000,这个地址是什么呢?
我们可以从之前的uboot编译中可以知道,真正的uboot入口是没有添加镜像头的,用hexdump可以看到
再看一下内存中0x87800000存的是什么
正是我们的无镜像头的uboot,这里就是Uboot的入口了,下一章我们从源码分析Uboot的启动流程。