Skip to main content

3.3 IMX6ULL映像文件

3.3 IMX6ULL映像文件

3.3.1 格式概述

​ 如果您有S3C2440或其他单片机的学习经验,可以知道程序的二进制版本,比如lcd.bin可以直接烧写到Flash上。它们是自启动的,什么意思?比如一上电,运行的是lcd.bin前面的代码,它会初始化内存,把自己从Flash上复制到内存里去执行。请记住:自己把自己复制到内存。 ​ 但是对于IMX6ULL,烧写在EMMC、SD/TF卡上的程序,并不能“自己复制自己”。一上电首先运行的是boot ROM上的程序,它从EMMC、SD/TF卡上把程序复制进内存里。 ​ 所以:boot ROM程序需要知道从启动设备哪个位置读程序,读多大的程序,复制到哪里去。 ​ 所以:启动设备上,不能仅仅烧写bin文件,需要在添加额外的信息。

​ 还有一个问题,IMX6ULL的boot ROM程序可以把程序读到DDR里,那需要先初始化DDR。每种板子接的DDR可能不一样,boot ROM程序需要初始化这些不同的DDR。boot ROM从哪里得到这些不同的参数?

​ 还有,IMX6ULL支持各种启动设备,比如各种Nor Flash。为了通用,boot ROM程序将会使用最保守的参数,也就是最慢的时序来访问Nor Flash。为加快启动程序,boot ROM程序可以根据我们提供的信息初始化硬件,让它以更优的参数运行。

​ 这些参数信息,被称为“Device Configuration Data”,设备配置数据(DCD),这些DCD将会跟bin文件一起打包烧写在启动设备上。boot ROM程序会从启动设备上读出DCD数据,根据DCD来写对应的寄存器以便初始化芯片。DCD中列出的是对某些寄存器的读写操作,我们可以在DCD中设置DDR控制器的寄存器值,可以在DCD中使用更优的参数设置必需的硬件。这样boot ROM程序就会帮我们初始化DDR和其他硬件,然后才可以把bin程序读到DDR中并运行。

​ 总结起来,烧写在EMMC、SD卡或是TF卡上的,除了程序本身,还有位置信息、DCD信息,这些内容合并成一个映像文件,如下图:

​ 这4部分内容合并成为一个映像文件,烧写在EMMC、SD卡或TF卡等启动设备的某个固定地址,boot ROM程序去这个固定地址读出映像文件。启动设备不同,固定地址不同,如下图:

3.3.2 格式详解

​ 先贴出一张图,然后再细细讲解:

​ 下面的讲解图中,列有C语言格式的结构体,这些结构体来源于U-boot的tools目录下的imximage.h。对于程序员,有时候看结构体可以更快地理解映像文件的格式。

​ (1). Image Vector Table(IVT):

​ IVT会被放在固定的地址,IVT中是一系列的地址,boot ROM程序会根据这些地址来确定映像文件中其他部分在哪里。

​ IVT格式如下:

​ 要注意的是上图中这4项:

​ a. header:

​ 里面有3项:tag、length、version。length表示IVT的大小,它是32字节。要注意是的,它是大字节序的。

​ b. entry:

​ 用户程序运行时第1条指令的地址,就是程序的链接地址、程序被复制到内存哪里

​ c. dcd:

​ 映像被复制到内存后,其中的DCD数据的地址。

​ d. boot data:

​ 映像被复制到内存后,其中的boot data的地址。

​ e. self:

​ 映像被复制到内存后,IVT自己所在的地址。

​ (2). Boot data:

​ 映像被复制到内存后,IVT自己所在的地址。

​ a. start:

​ 这是映像文件在内存中的地址,注意,它不等于IVT在内存中的地址。

​ 什么意思?假设IVT被保存在启动设备TF卡1024偏移地址处,IVT被复制到内存地址0x87000000,那么start=0x87000000-1024。

​ 所以start表示的是启动设备开头的数据,被复制到内存哪里去。

​ 从它的含义也可以推理出:boot ROM程序会把启动设备开头的数据,复制到内存;而不仅仅是从IVT开始复制。

​ b. length:

​ 保存在启动设备上的整个映像文件的长度,从0地址开始(不是从IVT开始)。

​ c. plugin:

​ 这是一个标记位,当它为1时表示这个映像文件是“plugin”,即插件。

​ boot ROM程序可以支持有限的启动设备,如果你想双持更多的启动设备比如网络启动、CDROM启动,就需要提供对应的驱动。这些驱动就是“plugin”,我们的教程不涉及,该标记位为0。

​ Boot data就是用来表示映像文件应该被复制到哪里去,以前它的大小。boot ROM程序就是根据它来把整个映像文件复制到内存去的。

​ (3). DCD:

​ DCD的作用在前面讲解过,简单地说就是设备的配置信息,里面保存有一些寄存器值。

​ 实际上DCD还可以更复杂,它支持多种命令:write data、check data、nop、unlock。我们可以通过write data命令写寄存器,通过check data命令等待寄存器就绪。

​ DCD格式如下:

​ DCD以Header开始,里面的TAG为0xD2表示它是DCD,里面还标明了DCD的大小、版本。

​ 接下来就是各个“CMD”,你可以在一个“CMD”里操作多个寄存器,比如在一个“write data command”中,写多个寄存器。

​ 以“write data command”为例简单介绍一下,它的格式为:

​ 上图中,TAG为0xCC表示这是“write data command”;Length表示命令的大小;Parameter的作用稍后再说。

​ 既然是写命令,那自然就有“地址、值”,上图中就是多个“Address、Value/Mask”。为何还有Mask?这要结合Parameter来讲解:

​ Parameter中b[2:0]用来表示写操作的字节数,是以字节、半字(2 byte),还是字(4 byte)来操作。

​ 而b[4]、b[3]决定了是写值(write value),清位(clear bitmask),还是设位(set bitmask)。

​ 对于其他命令,共格式可以参考IMX6UL的芯片手册,这里就不再介绍了。

​ (4). User code and data:

​ 就是用户程序或数据,原原本本地添加到映像文件里就可以。

​ https://github.com/NXPmicro/mfgtools

3.3.1 实例

​ 我们制作映像文件的目的什么?把我们自己的程序烧写到启动设备,让boot ROM程序启动它。

​ 所以制作映像文件的起点是:我们编写的程序。制作过程中各填值的计算方法如下图所示。

上图中各步骤细说如下:

① 确定入口地址entry:

我们的程序运行时要放在内存中哪一个位置,这是我们决定的。它被称为入口地址、链接地址。

② 确定映像文件在内存中的地址start:

boot ROM程序启动时,会把“initial load region”读出来,“initial load region”里含有IVT、Boot data、DCD。boot ROM根据DCD初始化设备后,再把整个映像文件读到内存。

在启动设备上,“initial load region”之后紧跟着我们的程序,反过来说就是我们程序的前面,放着“initial load region”。假设“initial load region”的大小为load_size,那么在内存中“initial load region”的位置start = entry – load_size。

注意:“initial load region”位于启动设备0位置,它的头部并不是IVT,而是一些无用的数据(或是分区信息)。

③ 确定IVT在内存中的地址self:

我们知道IVT在启动设备上某个固定的位置:ivt_offset。那么在内存中它的位置可以如下计算:

self = start + ivt_offset = entry – load_size + ivt_offset

④ 确定Boot data在内存中的地址boot_data:

IVT的大小是32字节,IVT之后就是Boot data,而IVT中的boot_data值表示Boot data在内存中的位置,计算如下:

boot_data = self + 32 = entry – load_size + ivt_offset + 32

⑤ 确定DCD在内存中的地址dcd:

Boot data的大小是12字节,Boot data之后就是DCD,而IVT中的dcd值表示DCD在内存中的位置,计算如下:

dcd = boot_data + 12 = entry – load_size + ivt_offset + 44

⑥ 写入DCD的数据:

DCD是用初始化硬件的,特别是初始化DDR。而DDR的初始化非常的复杂、专业,我们一般是使用硬件厂家提供的代码。

在后面的程序中你可以看到,我们是使用类似下面的指令来制作映象文件:

./tools/mkimage -n ./tools/imximage.cfg.cfgtmp -T imximage -e 0x80100000 -d led.bin led.imx

​ 上述命令中的imximage.cfg.cfgtmp就是厂家提供的,内部截取部分贴出来:

从上图也可以看到imximage.cfg.cfgtmp文件中基本是对寄存器的写操作。

​ mkimage程序来自u-boot,它会把imximage.cfg.cfgtmp中的内容转换为DCD数据。我们并不打算讲解DCD的内容,只需要了解它的大概作用:

a. 设置时钟:DDR也需要时钟,这很好理解

b. 设置引脚:DDR需要很多引脚

c. 设置DDR控制器:Multi-mode DDR controller (MMDC)

⑦ 写入用户程序

⑧ 经过上述7个步骤,整个映像文件就构造出来了,可以把它烧入启动设备。

​ 我们提供的示例程序001_led中有一个文件:led.img,它就是映象文件,可以直接烧入TF卡。用软件Hex Editor Neo打开led.img,选择doble word方式显示,可以看到如下内容,你可以自行验证一下映像文件中各个值。