ARM(IMX6U)裸机之I.MX6ULL启动头文件的详解
Posted 行稳方能走远
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ARM(IMX6U)裸机之I.MX6ULL启动头文件的详解相关的知识,希望对你有一定的参考价值。
参考:Linux之ARM(IMX6U)裸机之I.MX6ULL镜像烧写以及启动头文件的详解
作者:一只青木呀
发布时间: 2020-08-09 17:10:00
网址:https://blog.csdn.net/weixin_45309916/article/details/107895975
1.BOOT ROM做的事情
设置内核时钟为396MHz,使能MMU和Cache,使能L1cache、L2cache、MMU,目的就是为了加速启动。
从BOOT_CFG设置的外置存储中,读取image,然后做相应的处理。
详见参考手册第八章,如下。
2.IVT 和 Boot Data 数据
前面我们设置好 BOOT 以后就能从指定的设备启动了,但是你的设备里面得有代码啊,在LED灯实验中我们使用 imxdownload这个软件将 led.bin 烧写到了 SD 卡中。imxdownload 会在 led.bin前面添加一些头信息,重新生成一个叫做 load.imx 的文件,最终实际烧写的是 laod.imx。那么imxdownload 究竟做了什么? load.imx 和 led.bin 究竟是什么关系?
①、 Image vector table,简称 IVT, IVT 里面包含了一系列的地址信息,这些地址信息在ROM中按照固定的地址存放着。
②、 Boot data,启动数据,包含了镜像要拷贝到哪个地址,拷贝的大小是多少等等。
③、 Device configuration data,简称 DCD,设备配置信息,重点是 DDR3 的初始化配置。
④、用户代码可执行文件,比如 led.bin。 可以看出最终烧写到 I.MX6U 中的程序其组成为: IVT+Boot data+DCD+.bin。所以LED灯实验中的 imxdownload 所生成的 load.imx 就是在 led.bin 前面加上 IVT+Boot data+DCD。内部 BootROM 会将 load.imx 拷贝到 DDR 中,用户代码是要一定要从 0X87800000 这个地方开始的,因为链接地址为0X87800000, load.imx 在用户代码前面又有 3KByte 的 IVT+Boot Data+DCD 数据,下面会讲为什么是3KByte,因此 load.imx 在 DDR 中的起始地址就是 0X87800000-3072=0X877FF400
总结:我们编译出来的.bin 文件不能直接烧写到 SD 卡中,需要在.bin 文件前面加上 IVT、 Boot Data 和 DCD这三个数据块。这三个数据块是有指定格式的,我们必须按照格式填写,然后将其放到.bin 文件前面,最终合成的才是可以直接烧写到 SD卡中的文件。
load.imx 最前面的就是 IVT 和 Boot Data, IVT 包含了镜像程序的入口点、指向 DCD 的指针和一些用作其它用途的指针。内部 Boot ROM 要求 IVT 应该放到指定的位置,不同的启动设备位置不同,而 IVT 在整个 load.imx 的最前面,其实就相当于要求 load.imx 在烧写的时候应该烧写到存储设备的指定位置去。整个位置都是相对于存储设备的起始地址的偏移,如图
以 SD/EMMC 为例, IVT 偏移为 1Kbyte, IVT+Boot data+DCD 的总大小为 4KByte-1KByte=3KByte。假如 SD/EMMC 每个扇区为 512 字节,那么 load.imx 应该从第三个扇区开始烧写,前两个扇区要留出来。 load.imx 从第 3KByte 开始才是真正的.bin 文件。那么 IVT 里面究竟存放着什么东西呢? IVT 里面存放的内容如图:
SD卡为什么偏移1Kbyte(1K字节)?
SD卡前512字节保存了分区表分区信息,如果把SD卡前512字节写入数据的话,那么这个SD卡就废了。这里偏移了1K。
第一个存放的就是 header(头), header 格式如图
Tag 为一个字节长度,固定为 0XD1, Length 是两个字节,保存着 IVT 长度,为大端格式,也就是高字节保存在低内存中。最后的 Version 是一个字节,为 0X40 或者0X41
实际情况是不是这样的呢?我们用winhex 软件打开load.imx (前面点亮LED灯生成的)一看便知,winhex 可以直接查看一个文件的二进制格式数据。用winhex 打开以后的load.imxd 如图所示:
图是我们截取的load.imx 的一部分内容,从地址0X00000000~0X000025F,共608个字节的数据。我们将前44 个字节的数据按照4 个字节一组组合在一起就是:0X402000D1、0X87800000、0X00000000、0X877FF42C、0X877FF420、0X877FF400、0X00000000、0X00000000、
0X877FF000、0X00200000、0X00000000。这44 个字节的数据就是IVT 和Boot Data 数据,按照IVT 和Boot Data 所示的格式对应起来如表所示:
IVI结构 | 数据 | 描述 |
---|---|---|
header | 0X402000D1 | 根据 header 格式,第一个字节 Tag 为0XD1,第二三这两个字节为 IVT 大小,为大端模式,所以 IVT 大小为 0X20=32 字节。第四个字节为 0X40 |
entry | 0X87800000 | 入口地址,也就是镜像第一行指令所在的位置。0X87800000 就是我们的链接地址。 |
reserved1 | 0X00000000 | 未使用,保留。 |
dcd | 0X877FF42C DCD | 地址,镜像地址为 0X87800000, IVT+BootData+DCD 整个大小为 3KByte。因此 load.imx 的起始地址就是 0X87800000-0XC00=0X877FF400。因此 DCD 起始地址相对于 load.imx 起始地址的偏移就是0X877FF42C-0X877FF400=0X2C,也就是说 0X2C 这个地址开始就是 DCD 数据了。 |
boot data | 0X877FF420 | boot 地址, header 里面已经设置了 IVT 大小是 32个 字 节 , 所 以 boot data 的 地 址 就 是0X877FF400+32=0X877FF420。 |
self | 0X877FF400 | IVT 复制到 DDR 中以后的首地址。 |
csf | 0X00000000 | CSF 地址。 |
reserved2 | 0X00000000 | 保留,未使用 |
Boot Data 的数据格式如图
BOOT DATA结构 | 数据 | 描述 |
---|---|---|
start | 0X877FF000 | 整个 load.imx 的起始地址,包括前面 1KByte 的地址偏移。 |
length | 0X00200000 | 镜像大小,这里设置 2MByte。镜像大小不能超过2MByte。 |
plugin | 0X00000000 | 插件 |
我们详细的列出了 load.imx 的 IVT+Boot Data 每 32 位数据所代表的意义。这些数据都是由 imxdownload 这个软件添加进去的。
3.DCD数据
复位以后, I.MX6U 片内的所有寄存器都会复位为默认值,但是这些默认值往往不是我们想要的值,而且有些外设我们必须在使用之前初始化它。为此 I.MX6U 提出了一个 DCD(DeviceConfig Data)的概念来配置寄存器,和 IVT、 Boot Data 一样, DCD 也是添加到 load.imx 里面的,紧跟在 IVT和 Boot Data 后面, IVT 里面也指定了 DCD 的位置。 DCD 其实就是 I.MX6U 寄存器地址和对应的配置信息集合, Boot ROM 会使用这些寄存器地址和配置集合来初始化相应的寄存器,比如开启某些外设的时钟、初始化 DDR 等等。 DCD 区域不能超过 1768Byte, DCD 区域结构如图:
DCD 的 header 和 IVT 的 header 类似,结构如图:
其中 Tag 是单字节,固定为 0XD2, Length 为两个字节,表示 DCD 区域的大小,包含 header,同样是大端模式, Version 是单字节,固定为 0X40 或者 0X41
DCD区域结构图中的 CMD 就是要初始化的寄存器地址和相应的寄存器值, 结构如图
Tag 为一个字节,固定为 0XCC。 Length 是两个字节,包含写入的命令数据长度,包含 header,同样是大端模式。 Parameter 为一个字节,这个字节的每个位含义如图
bytes 表示是目标位置宽度,单位为 byte,可以选择 1、 2、和 4 字节。 flags是命令控制标志位。
Address 和 Vlalue/Mask 就是要初始化的寄存器地址和相应的寄存器值,注意采用的是大端模式(高字节的数据在低位)! 在分析 IVT 的时候我们就已经说过了, DCD数据是从 0X2C 地址开始的。根据我们分析的 DCD 结构可以得到 load.imx 的 DCD数据如表
DCD结构 | 数据 | 描述 |
---|---|---|
header | 0X40E801D2 | 根据的 header 格式,第一个字节 Tag 为 0XD2,第二和三这两个字节为 DCD 大小,为大端模式,所以 DCD 大小为 0X01E8=488 字节。第四个字节为 0X40 |
Write Data Command | 0X04E401CC | 第一个为 Tag,固定为 0XCC,第二和三这两个字节是大端模式的命令总长度,为 0X01E4=484 个字节。第四个字节是 Parameter,为 0X04,表示目标位置宽度为 4 个字节。 |
Address | 0X020C4068 | 寄存器 CCGR0 地址 |
Value | 0XFFFFFFFF | 要写入寄存器 CCGR0 的值,表示打开 CCGR0 控制的所有外设时钟。 |
…… | …… | CCGR1~CCGR5 这些寄存器的地址和值。 |
Address | 0X020C4080 | 寄存器 CCGR6 地址 |
Value | 0XFFFFFFFF | 要写入寄存器 CCGR6 的值,表示打开 CCGR6 控制的所有外设时钟。 |
Address | 0X020E04B4 | 寄存器 IOMUXC_SW_PAD_CTL_GRP_DDR_TYPE 寄存器地址。 |
Value | 0X000C0000 | 设置 DDR 的所有 IO 为 DDR3 模式。 |
Address | 0X020E04AC | 寄存器 IOMUXC_SW_PAD_CTL_GRP_DDRPKE 地址。 |
Value | 0X00000000 | 所有 DDR 引脚关闭 Pull/Keeper 功能。 |
Address | 0X020E027C | 寄存器 IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK0_P |
Value | 0X00000030 | DRAM_SDCLK0_P 引脚为 R0/6。 |
…… | …… | 全部是 DDR 引脚设置 |
Address | 0X020E0248 | 寄存器 IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM1 |
Value | 0X00000030 | DRAM_DQM1 引脚驱动能力为 R0/6 |
Address | 0X021B001C | MMDC_MDSCR 寄存器 |
Value | 0X00008000 | MMDC_MDSCR 寄存器值 |
…… | …… | MMDC 相关寄存器地址及其寄存器值。 |
Address | 0X021B0404 | MMDC_MAPSR 寄存器 |
Value | 0X00011006 | MMDC_MAPSR 寄存器配置值 |
Address | 0X021B001C | MMDC_MDSCR 寄存器 |
Value | 0X00000000 | MMDC_MDSCR 寄存器清零 |
从图 中可以看出, DCD 里面的初始化配置主要包括三方面:
①、设置 CCGR0~CCGR6 这 7 个外设时钟使能寄存器,默认打开所有的外设时钟。
②、配置 DDR3 所用的所有 IO。
③、配置 MMDC 控制器,初始化 DDR3
以上是关于ARM(IMX6U)裸机之I.MX6ULL启动头文件的详解的主要内容,如果未能解决你的问题,请参考以下文章