linux系列目录:
linux基础篇(一)——GCC和Makefile编译过程
linux基础篇(二)——静态和动态链接
ARM裸机篇(一)——i.MX6ULL介绍
ARM裸机篇(二)——i.MX6ULL启动过程
ARM裸机篇(三)——i.MX6ULL第一个裸机程序
ARM裸机篇(四)——重定位和地址无关码
ARM裸机篇(五)——异常和中断
文章目录
- 一、 i.MX6ULL启动流程
- 二、i.MX6ULL镜像格式
- 三、镜像实例
- 四、制作镜像
- 五、烧写镜像
一、 i.MX6ULL启动流程
I.MX6U 支持多种启动方式以及启动设备,比如可以从 SD/EMMC、 NAND Flash、 QSPI Flash等启动。
i.MX6UL完整的启动流程如下图所示,完成启动任务的代码位于0x0000 0000 地址处的Boot ROM。
启动流程过程大致可分为六步。①检查CPU的ID ,②检查复 位状态,③获取启动方式,④加载程序映像,⑤校验映像,⑥跳转到映像去执行。
i.MX6ULL有四个启动模式,如下表,具体使用哪种启动模式通过内部寄存器 BOOT_MODE 中的值来选择,如图:
当 BOOT_MODE 设置为内部 BOOT 模式以后,所谓“内部”是相对于“Serial Download”来说的,“内部”可以认为是 i.MX6ULL 支持的启动存储设备,例如 emmc、 nandflash、 SD card、norFlash 等等。具体从那种“内部”设备启动,由 BOOT_CFG1[7:4] 决定,如下表所示。表内部启动方式选择:
知道启动方式后 Boot ROM 代码并不能立即加载启动映像,因为我们的代码保存在芯片外部存储设备,从这些存储设备读数据之前首先要进行初始化。在 Boot ROM 程序根据保存在芯片中的默认配置信息配置这些存储器接口。
I.MX6ULL 的最终可烧写文件组成如下:
①、 Image vector table,简称 IVT, IVT 里面包含了一系列的地址信息,这些地址信息在ROM 中按照固定的地址存放着。
②、 Boot data,启动数据,包含了镜像要拷贝到哪个地址,拷贝的大小是多少等。
③、 Device configuration data,简称 DCD,设备配置信息,重点是 DDR3 的初始化配置。
④、用户代码可执行文件,比如 led.bin。
最终烧写到 I.MX6U 中的程序其组成为: IVT+Boot data+DCD+.bin。
这4部分内容合并成为一个映像文件,烧写在EMMC、SD卡或TF卡等启动设备的某个固定地址,boot ROM程序去这个固定地址读出映像文件。启动设备不同,固定地址不同,如下图:
制作映像文件的起点是:我们编写的程序。制作过程中各项值的计算方法如下图所示。
按照上述的配置,板子上电后Boot Rom会根据上述的配置初始化时钟和DDR3,然后会将映像文件从启动设备(TF卡、eMMC)自动拷贝到DDR3内存上。Boot Rom应该将映像文件拷贝到内存的哪个位置,上述的配置文件已经规定好了,拷贝到DDR3中的位置和大小由Boot data数据决定,用户.bin文件的起始地址由地址entry决定,需要在链接脚本中手动配置。假设.bin文件的起始地址为0x87800000。复制结束后,CPU会从这个地址读取第一条指令开始执行程序。
假设我们已经有了一个led.S的裸机程序,然后经过编译链接到0x87800000这个地址,使用objcopy工具转换成bin文件:
arm-none-eabi-gcc -c led.S -o led.o arm-none-eabi-ld -Ttext 0x87800000 led.o -o led.elf arm-none-eabi-objcopy -O binary -S -g led.elf led.bin
- 确定入口地址entry:
我们的程序运行时要放在内存中哪一个位置,这是我们决定的,由于我们把程序链接到了0x87800000,所以此地址就是程序的入口地址。 - 确定映像文件在内存中的地址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=0x87800000 - 0x1000 = 0x877FF000。 - 确定IVT在内存中的地址self:
self = start + ivt_offset = 0x877FF000 + 0x400 = 0x877FF400 - 确定Boot data在内存中的地址boot_data:
IVT结构的大小是32个字节,IVT之后就是Boot data,而IVT中的boot_data值表示Boot data在内存中的位置,计算如下:
boot_data = self + 32 =0x877FF400+32=0x877FF420 - 确定DCD在内存中的地址dcd:
Boot data结构的大小是12字节,Boot data之后就是DCD,而IVT中的dcd值表示DCD在内存中的位置,计算如下:
dcd = boot_data + 12 = 0x877FF420 + 0x0C = 0x877FF42C - 写入DCD的数据
DCD是用初始化硬件的,特别是初始化DDR。而DDR的初始化非常的复杂、专业,我们一般是使用硬件厂家提供的代码。 - 写入用户程序
经过上述7个步骤,映像文件就构建出来了,可以把它烧入启动设备。
把上述步骤,可以写成如下代码,自动为我们完成映像的制作:
imxdownload.c:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define SHELLCMD_LEN (200)
#define BIN_OFFSET (3072)
#define PRINT_TAB 0
const int imx6_512mb_ivtdcd_table[256] = {
0x402000D1,0x87800000,0x00000000,0x877FF42C,0x877FF420,0x877FF400,0x00000000,0x00000000,
0x877FF000,0x00200000,0x00000000,0x40E801D2,0x04E401CC,0x68400C02,0xFFFFFFFF,0x6C400C02,
0xFFFFFFFF,0x70400C02,0xFFFFFFFF,0x74400C02,0xFFFFFFFF,0x78400C02,0xFFFFFFFF,0x7C400C02,
0xFFFFFFFF,0x80400C02,0xFFFFFFFF,0xB4040E02,0x00000C00,0xAC040E02,0x00000000,0x7C020E02,
0x30000000,0x50020E02,0x30000000,0x4C020E02,0x30000000,0x90040E02,0x30000000,0x88020E02,
0x30000C00,0x70020E02,0x00000000,0x60020E02,0x30000000,0x64020E02,0x30000000,0xA0040E02,
0x30000000,0x94040E02,0x00000200,0x80020E02,0x30000000,0x84020E02,0x30000000,0xB0040E02,
0x00000200,0x98040E02,0x30000000,0xA4040E02,0x30000000,0x44020E02,0x30000000,0x48020E02,
0x30000000,0x1C001B02,0x00800000,0x00081B02,0x030039A1,0x0C081B02,0x0B000300,0x3C081B02,
0x44014801,0x48081B02,0x302C4040,0x50081B02,0x343E4040,0x1C081B02,0x33333333,0x20081B02,
0x33333333,0x2C081B02,0x333333F3,0x30081B02,0x333333F3,0xC0081B02,0x09409400,0xB8081B02,
0x00080000,0x04001B02,0x2D000200,0x08001B02,0x3030331B,0x0C001B02,0xF3526B67,0x10001B02,
0x630B6DB6,0x14001B02,0xDB00FF01,0x18001B02,0x40172000,0x1C001B02,0x00800000,0x2C001B02,
0xD2260000,0x30001B02,0x23106B00,0x40001B02,0x4F000000,0x00001B02,0x00001884,0x90081B02,
0x00004000,0x1C001B02,0x32800002,0x1C001B02,0x33800000,0x1C001B02,0x31800400,0x1C001B02,
0x30802015,0x1C001B02,0x40800004,0x20001B02,0x00080000,0x18081B02,0x27020000,0x04001B02,
0x2D550200,0x04041B02,0x06100100,0x1C001B02,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
};
const int imx6_256mb_ivtdcd_table[256] = {
0x402000D1,0x87800000,0x00000000,0x877FF42C,0x877FF420,0x877FF400,0x00000000,0x00000000,
0x877FF000,0x00076000,0x00000000,0x40E801D2,0x04E401CC,0x68400C02,0xFFFFFFFF,0x6C400C02,
0xFFFFFFFF,0x70400C02,0xFFFFFFFF,0x74400C02,0xFFFFFFFF,0x78400C02,0xFFFFFFFF,0x7C400C02,
0xFFFFFFFF,0x80400C02,0xFFFFFFFF,0xB4040E02,0x00000C00,0xAC040E02,0x00000000,0x7C020E02,
0x30000000,0x50020E02,0x30000000,0x4C020E02,0x30000000,0x90040E02,0x30000000,0x88020E02,
0x30000C00,0x70020E02,0x00000000,0x60020E02,0x30000000,0x64020E02,0x30000000,0xA0040E02,
0x30000000,0x94040E02,0x00000200,0x80020E02,0x30000000,0x84020E02,0x30000000,0xB0040E02,
0x00000200,0x98040E02,0x30000000,0xA4040E02,0x30000000,0x44020E02,0x30000000,0x48020E02,
0x30000000,0x1C001B02,0x00800000,0x00081B02,0x030039A1,0x0C081B02,0x04000000,0x3C081B02,
0x3C013C01,0x48081B02,0x38324040,0x50081B02,0x28304040,0x1C081B02,0x33333333,0x20081B02,
0x33333333,0x2C081B02,0x333333F3,0x30081B02,0x333333F3,0xC0081B02,0x09409400,0xB8081B02,
0x00080000,0x04001B02,0x2D000200,0x08001B02,0x3030331B,0x0C001B02,0xF352433F,0x10001B02,
0x630B6DB6,0x14001B02,0xDB00FF01,0x18001B02,0x40172000,0x1C001B02,0x00800000,0x2C001B02,
0xD2260000,0x30001B02,0x23104300,0x40001B02,0x47000000,0x00001B02,0x00001883,0x90081B02,
0x00004000,0x1C001B02,0x32800002,0x1C001B02,0x33800000,0x1C001B02,0x31800400,0x1C001B02,
0x30802015,0x1C001B02,0x40800004,0x20001B02,0x00080000,0x18081B02,0x27020000,0x04001B02,
0x2D550200,0x04041B02,0x06100100,0x1C001B02,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
};
void message_print(void)
{
printf("I.MX6ULL bin download softwarern");
printf("Edit by:zuozhongkairn");
printf("Date:2019/6/10rn");
printf("Version:V1.1rn");
printf("log:V1.0 initial version,just support 512MB DDR3rn");
printf(" V1.1 and support 256MB DDR3rn");
}
int main(int argc, char *argv[])
{
FILE *fp;
unsigned char *buf;
unsigned char *cmdbuf;
int nbytes, filelen;
int i = 0, j = 0;
int ddrsize = 0;
message_print();
if((argc != 3) && (argc != 4)){
printf("Error Usage! Reference Below:rn");
printf("sudo ./%s <-512m or -256m> rn", argv[0]);
return -1;
}
for(i = 0; i < argc; i++)
{
char *param = argv[i];
if(param[0] != '-')
continue;
if(strcmp(param, "-256m") == 0)
ddrsize = 1;
else if(strcmp(param, "-512m") == 0)
ddrsize = 0;
}
if(argc == 3)
ddrsize = 0;
fp = fopen(argv[1], "rb");
if(fp == NULL){
printf("Can't Open file %srn", argv[1]);
return -1;
}
fseek(fp, 0L, SEEK_END);
filelen = ftell(fp);
fseek(fp, 0L, SEEK_SET);
printf("file %s size = %dBytesrn", argv[1], filelen);
buf = malloc(filelen + BIN_OFFSET);
if(buf == NULL){
printf("Mem Malloc Failed!rn");
fclose(fp);
return -1;
}
memset(buf, 0, filelen + BIN_OFFSET);
fread(buf + BIN_OFFSET, 1, filelen, fp);
fclose(fp);
#if PRINT_TAB
printf("IVT DCD Table:rn");
for(i = 0; i < 1024/32; i++){
for(j = 0; j < 8; j++)
{
printf("0X%08X,",*(int *)(buf + BIN_OFFSET + (((i * 8) + j) * 4)));
}
printf("rn");
}
free(buf);
return 0;
#endif
if(ddrsize == 0) {
printf("Board DDR SIZE: 512MBrn");
memcpy(buf, imx6_512mb_ivtdcd_table, sizeof(imx6_512mb_ivtdcd_table));
}
else if (ddrsize == 1) {
printf("Board DDR SIZE: 256MBrn");
memcpy(buf, imx6_256mb_ivtdcd_table, sizeof(imx6_256mb_ivtdcd_table));
}
printf("Delete Old load.imxrn");
system("rm -rf load.imx");
printf("Create New load.imxrn");
system("touch load.imx");
fp = fopen("load.imx", "wb");
if(fp == NULL){
printf("Cant't Open load.imx!!!rn");
free(buf);
return -1;
}
nbytes = fwrite(buf, 1, filelen + BIN_OFFSET, fp);
if(nbytes != (filelen + BIN_OFFSET)){
printf("File Write Error!rn");
free(buf);
fclose(fp);
return -1;
}
free(buf);
fclose(fp);
cmdbuf = malloc(SHELLCMD_LEN);
sprintf(cmdbuf, "sudo dd iflag=dsync oflag=dsync if=load.imx of=%s bs=512 seek=2",argv[2]);
printf("Download load.imx to %s ......rn", argv[2]);
system(cmdbuf);
free(cmdbuf);
return 0;
}
编译:
gcc imxdownload.c -o imxdownload
使用方法:
sudo ./imxdownload <-512m or -256m>
推荐在usr/local/bin 文件夹下建立软链接,后续可以直接使用imxdownload命令:
sudo ln -s ~/imx6ull/tools/imxdownload/imxdownload /usr/local/bin/imxdownload
测试:
将USB读卡器插入电脑后,默认连接到主机,将鼠标放到USB图标上(虚拟机右下角状态栏), 单击鼠标右键如下所示,选择将读卡器连接到虚拟机上。
在将读卡器连接到虚拟机之后,使用lsblk查看,增加出来的设备就是我们内存卡的标识名。
使用imxdownload命令进行烧写:imxdownload led.bin /dev/sdb



