26. Uboot启动流程分析——上

26.1. 前言

本章主要讲解CPU上电到Uboot(或裸机)入口的启动流程和各个阶段实现的功能简单分析一下,主要是一些配置相关的寄存器地址与寄存器值,本教程提供给对启动流程好奇的同学学习,初学者仅当了解即可不影响后续的镜像构建。 本章内容也为个人见解,如有不对之处欢迎指出

26.2. 启动流程简介

上电 —> 设备初始化 —> 启动设备 —> 镜像头 —> Uboot入口

26.3. 设备初始化

26.3.1. 简述

这里的功能主要是原厂的固化在芯片内的程序的功能:简单初始化一下总线资源,再通过外部引脚判断从什么类型的flash中读取数据进行外设的初始化

26.3.2. 内存映射

首先需要先明确的是imx6ull里是带有ROM和RAM的,我们称它为iROM和iRAM。

未找到图片internal_rom_ram

iROM作用:存储异常向量表,HAB API向量表,ROM API向量表,日志缓冲区,固化的出厂程序

iRAM作用:运行出厂程序和镜像4K头部数据

小知识:这里的OCRAM Free Area在启动后是可以在Uboot使用的。

26.3.3. 初始化引导模块

主要功能如下

未找到图片qdmk

初始化了大部分的总线,为下面读取外部存储做准备。

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选择)

未找到图片fuse0 未找到图片fuse1 未找到图片fuse2

26.4.3. 镜像头读取流程分析

本小节主要是讲解各个Flash是如何找到镜像头的

镜像头是指IVT,Boot data,Device configuration data(DCD),往下我们简称镜像头。

26.4.3.1. NOR

未找到图片nor_ivt

该flash支持XIP可以在片上运行程序,需要注意的是NOR只能像RAM一样读取数据但不能像RAM一样写入,写入还得像NAND那样擦除再写入,所以其镜像头的加载可以是整个空间

然后根据镜像头配置好时钟和各种外设(内置外设),具体详细的镜像头分析将在后面讲解。

26.4.3.2. OneNAND

未找到图片onenand_ivt

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_firmware1_startingPage

我们将NAND的头100K数据提取出来看一下

未找到图片nand_firmware1_startingPage_putty

可以看的出,这里给出的值为 00 02

根据大小端可以知道,相应值为0x200,但是这个并不是指在NAND中的地址,而是指页数

还需要一个参数是页大小,页大小可以从NAND数据手册上找到

未找到图片NAND_datas

也可以从uboot的命令界面输入 nand info 查看

1
nand info
未找到图片uboot_nand_info

还可以根据FCB描述的NAND参数进行计算

未找到图片yhsc_PageDataSize 未找到图片pytty_pagesize

则可以算出页大小=0x1000=4096byte

地址=页数*页大小(byte)=0x200(512)*0x1000(4*1024)=0x200000(2097152)

现在有了入口地址,我们去看看0x200000在NAND中存放的是什么

未找到图片putty_nand_0x200000

看过4K数据头的同学对这个不会陌生,这个就是我们说的镜像头。

这个emmc版本的uboot头部数据,与NAND的非常像。

未找到图片jxt_mmc

这里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原则。

未找到图片mmc_ivt_set

这1K里包含了MBR表,主要记录分区信息

未找到图片MBR

既然讲到MBR表,我们就讲讲MMC/SD卡是如何分区的吧。

MBR表中有一块存储DPT的表,DPT中包含了分区信息

未找到图片DPT_55aa 未找到图片MBR_analyse

这是我SD卡的分区情况,可以在Linux下用fdisk -l查看

未找到图片fdisk_mmc

红色的为逻辑起始扇区:即第9,10,11,12字节的内容,0x2000=8192

绿色的为扇区数:即第13,14,15,16字节内容,0x14000=81920

蓝色的为结束扇区:逻辑扇区+扇区数-1=90111

黄色的为分区类型:即第5字节内容,如图0e(第二扇区为83),则ID为e(第二扇区为83)

那应该从0x400(1K)往后的地址就是我们要找的镜像头了

未找到图片jxt_mmc_sdka

也确实如此

26.4.3.5. Quad SPI flash

与MMC较为相似,之后补充

26.4.3.6. EEPROM

与MMC较为相似,之后补充

26.5. 镜像头分析

镜像头的作用主要是,对外置DDR进行初始化,时钟的设置,镜像的大小,uboot(裸机)的入口地址,CPU的电源控制等。具体的功能我已经总结到了如下的图中。

这里我提供一份mmc的uboot,可以在Linux下使用hexduemp进行查看,也可以对照着我提供的图与镜像头图一起看。

uboot

未找到图片uboot_hex

可以将本图保持放大观看

未找到图片IVT

26.6. Uboot入口

在镜像头中有一个名为entry地址0x87800000,这个地址是什么呢?

我们可以从之前的uboot编译中可以知道,真正的uboot入口是没有添加镜像头的,用hexdump可以看到

未找到图片realuboot

再看一下内存中0x87800000存的是什么

未找到图片ubootrukou

正是我们的无镜像头的uboot,这里就是Uboot的入口了,下一章我们从源码分析Uboot的启动流程。