失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > imx8mq-evk快速启动-bootloader时间优化(eMMC启动)

imx8mq-evk快速启动-bootloader时间优化(eMMC启动)

时间:2020-06-24 12:58:49

相关推荐

imx8mq-evk快速启动-bootloader时间优化(eMMC启动)

一、imx8mq的bootloader分析

关于imx8mq的bootloader系列,可以参考前面的三篇文章

imx8mq - u-boot-spl启动分析

imx8mq - bootloader编译过程

imx8mq - u-boot启动分析

Bootloader的启动流程图

nxp提供的imx8mq启动方式Bootloader方式如上图所示。

其中:

Power on sequence为芯片上电的上电过程,此部分时间基本上为一个定值,也没有什么时间上的优化空间BootROM:固化在SOC上的一段启动引导代码,用于引导系统根据BOOTMODE和BOOTCFG配置引导系统以不同的方式从不同的启动设备启动。也没有什么优化空间。毕竟代码已经固化死了。Signal hdmi:一段初始化HDMI设备的固化代码,对HDMI部分不熟悉,而且,NXP上提供的也是bin文件。所以,基本也没什么优化空间。spl-boot:用于引导uboot初始化SOC必须的部分,比如DDR,然后复制bl31,uboot,到系统内存,引导下一步启动bl31。这部分可以进行一些硬件IO时间的优化,比如读取EMMC优化,串口打印优化。bl31:ATF部分代码,用于引导RAM-v8启动kernel。这一段没什么研究。虽然提供源码,但是本次优化不对这部分进行优化。uboot:这里为Bootloader阶段优化的主要优化点。可以优化的地方有很多。Uboot的主要作用是引导kernel启动,其他部分都可以进行裁剪,比如串口打印,USB相关初始化,网络初始化,QSPI部分初始化,一些cmd裁剪。镜像文件拷贝的IO优化等等

二、uboot快速启动方案:

1.方案讨论

u-boot作为一款通用的Bootloader,其支持多种架构系列,支持多种嵌入式系统内核的引导,还具有丰富的功能配置,调试组件等等。所以,在系统硬件调试阶段,往往可以发挥强大的作用。

但是,对于有快启要求下,就需要对u-boot进行优化与裁剪了。甚至,对于一些简单的SOC架构,如S3C2440,完全可以自己写出一个最小的Bootloader,具备以下功能。可以参考韦老师的最小Bootloader

SOC级硬件初始化初始化DDR初始化启动设备接口以及启动设备初始化从启动设备读取内核和设备树到内存跳转启动内核

但是对于imx8系列的处理器,要从0编写一个Bootloader难度较大。还是选择在原有u-boot架构上根据以上思路进行裁剪优化就行。

2. imx8系列的u-boot启动内核

根据图一所示的启动流程,能够动手优化的就u-boot的spl阶段和第二阶段。中间还有一段atf部分代码。本次优化的思路是,直接使用dd命令把内核和设备树镜像文件烧写到eMMC的硬件分区User的固定偏移地址上。然后spl读取内核和设备树到内存,在跳转到atf部分代码。u-boot第二阶段直接使用一个简单的跳转指令代替。下面一一列出代码:

第一部分:SPL阶段把所需镜像文件拷贝到内存

这里代码有点多,不是实际需要就不用看了,代码作用就是把spl后面的bl31,用来跳转kernel的miniboot,kernel,dtb四个镜像文件到内存指定位置上。

#include <mmc.h>#include <mapmem.h>#include <div64.h>#include <linux/math64.h>/*------------------------------------------------------------------------------------------------*/#define MINIBOOT_LOAD_ADDR((void*)0x40200000)#define ATF_LOAD_ADDR((void*)0x00910000)#define DTB_LOAD_ADDR((void*)0x43000000)#define IMAGE_LOAD_ADDR((void*)0x40480000)#define ATF_MMC_SECTOR_OFFSET 0x00000400 //1024#define MINIBOOT_MMC_SECTOR_OFFSET0x00000800//2048#define DTB_MMC_SECTOR_OFFSET0x00001000 //4096#define IMAGE_MMC_SECTOR_OFFSET0x00005000 //20480#define ATF_SECTOR_COUNT0x00000064//51.2KB#define MINIBOOT_SECTOR_COUNT0x00000001//512B#define DTB_SECTOR_COUNT0x00000064//51.2KB#define IMAGE_SECTOR_COUNT0x0000C800//25MB (no use)#define EMMC_PART0#define LINUX_ARM64_IMAGE_MAGIC0x644d5241#define FDT_MAGIC0xd00dfeed/* 4: version, 4: total size */struct spl_boot_opr{ulong ep;/* entry point if OS */ulong dp;/* dtb point in ram */};/* See Documentation/arm64/booting.txt in the Linux kernel */struct Image_header {uint32_tcode0;/* Executable code */uint32_tcode1;/* Executable code */uint64_ttext_offset;/* Image load offset, LE */uint64_timage_size;/* Effective Image size, LE */uint64_tres1;/* reserved */uint64_tres2;/* reserved */uint64_tres3;/* reserved */uint64_tres4;/* reserved */uint32_tmagic;/* Magic number */uint32_tres5;};static void dump_image_head(struct Image_header *ih){printf("Image_header->code0\t:0x%x\n",ih->code0);printf("Image_header->code1\t:0x%x\n",ih->code1);printf("Image_header->text_offset\t:0x%llx\n",ih->text_offset);printf("Image_header->image_size\t:0x%llx\n",ih->image_size);printf("Image_header->magic\t:0x%x\n",ih->magic);}static void dump_dtb_head(struct fdt_header *fdt){printf("fdt_header->magic\t:0x%x\n",fdt_magic(fdt));printf("fdt_header->totalsize\t:0x%x\n",fdt_totalsize(fdt));printf("fdt_header->version\t:0x%x\n",fdt_version(fdt));}static int booti_verify(struct spl_boot_opr *op){struct Image_header *ih;struct fdt_header *dh;ih = (struct Image_header *)map_sysmem(op->ep, 0);dh = (struct fdt_header *)map_sysmem(op->dp, 0);if (ih->magic != le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC)) {printf("Bad Linux ARM64 Image magic!\n");dump_image_head(ih);return -1;}if (fdt_magic(dh) != FDT_MAGIC){printf("Bad DTB magic!\n\tfdt_magic(fdt) = 0x%x;\tFDT_MAGIC = 0x%x\n",fdt_magic(dh) ,FDT_MAGIC);return -1;}return 0;}static int spl_mmc_find_device(struct mmc **mmcp, u32 boot_device){#ifdef CONFIG_DM_MMCstruct udevice *dev;#endifint err, mmc_dev;mmc_dev = 0;//spl_mmc_get_device_index(boot_device);if (mmc_dev < 0)return mmc_dev;err = mmc_initialize(NULL);if (err) {#ifdef CONFIG_SPL_LIBCOMMON_SUPPORTprintf("spl: could not initialize mmc. error: %d\n", err);#endifreturn err;}#ifdef CONFIG_DM_MMCerr = uclass_get_device(UCLASS_MMC, mmc_dev, &dev);if (!err)*mmcp = mmc_get_mmc_dev(dev);#else*mmcp = find_mmc_device(mmc_dev);err = *mmcp ? 0 : -ENODEV;#endifif (err) {#ifdef CONFIG_SPL_LIBCOMMON_SUPPORTprintf("spl: could not find mmc device. error: %d\n", err);#endifreturn err;}return 0;}//#define TIME_DEBUGstatic int read_image(struct spl_boot_opr *op){struct mmc *mmc = NULL;int dev= 0 , part = 0;unsigned long count, times;int err = 0;struct Image_header *ih;struct fdt_header *dh;void *dtb_desc, *image_desc;dtb_desc = DTB_LOAD_ADDR;image_desc = IMAGE_LOAD_ADDR;ih = IMAGE_LOAD_ADDR;dh = DTB_LOAD_ADDR;//寻找mmc控制器结构体printf("spl: Start read_image ,\n find mmc from BOOT_DEVICE_MMC1\n");err = spl_mmc_find_device(&mmc, BOOT_DEVICE_MMC1);if (err){printf("spl: can't find any mmc devide from : %d\n\terr:%d\n", BOOT_DEVICE_MMC1,err);return -1;}//mmc接口初始化printf("spl: Get mmc:%s and then init mmc\n",mmc->cfg->name);mmc->has_init = 0;err = mmc_init(mmc);if (err) {printf("spl: mmc init failed with error: %d\n", err);return -1;}//选择用户分区part = EMMC_PART;err = blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part);printf("switch to partitions #%d, %s\n", part, (!err) ? "OK" : "ERROR");if (err < 0){printf("spl: Switch mmc part failed with error: %d\n", err);return -1;}if (mmc->part_config == MMCPART_NOAVAILABLE)printf("mmc%d is current device\n", dev);elseprintf("mmc%d(part %d) is current device\n", dev, mmc_get_blk_desc(mmc)->hwpart);#ifdef TIME_DEBUG //读取Image的头部信息,判断Image大小times = get_timer(0);count = blk_dread(mmc_get_blk_desc(mmc), IMAGE_MMC_SECTOR_OFFSET, 1, ih);times = get_timer(times);if (count != 1){printf("spl: Read Image head error: %ld\n", count);return -1;}printf("%lu bytes read in %lu ms", count * 512, times);if (times > 0) {puts(" (");print_size(div_u64(count * 512, times) * 1000, "/s");puts(")");}puts("\n");//打印头部信息dump_image_head(ih);if (ih->image_size > 0x1E00000){ // > 30MBprintf("Image size > 0x1E00000 \n");return -1;}//读取Image到内存times = get_timer(0);count = blk_dread(mmc_get_blk_desc(mmc), IMAGE_MMC_SECTOR_OFFSET, ih->image_size / 512 + 1 , image_desc);times = get_timer(times);if (count != (ih->image_size / 512 + 1)) {printf("spl: can't read Image from mmc;count:%ld\n", count);return -1;}printf("%lu bytes read in %lu ms", count * 512, times);if (times > 0) {puts(" (");print_size(div_u64(count * 512, times) * 1000, "/s");puts(")");}puts("\n");//读取dtb到内存times = get_timer(0);count = blk_dread(mmc_get_blk_desc(mmc), DTB_MMC_SECTOR_OFFSET, DTB_SECTOR_COUNT, DTB_LOAD_ADDR);times = get_timer(times);if (count != (fdt_totalsize(dh) / 512 + 1)){printf("spl: can't read dtb from mmc;count:%ld\n", count);return -1;}printf("%lu bytes read in %lu ms", count * 512, times);if (times > 0) {puts(" (");print_size(div_u64(count * 512, times) * 1000, "/s");puts(")");}puts("\n");//读取atf到内存times = get_timer(0);count = blk_dread(mmc_get_blk_desc(mmc), ATF_MMC_SECTOR_OFFSET, ATF_SECTOR_COUNT, ATF_LOAD_ADDR);times = get_timer(times);if (count != ATF_SECTOR_COUNT){printf("spl: can't read bl31 from mmc;count:%ld\n", count);return -1;}printf("%lu bytes read in %lu ms", count * 512, times);if (times > 0) {puts(" (");print_size(div_u64(count * 512, times) * 1000, "/s");puts(")");}puts("\n");//读取miniboot到内存times = get_timer(0);count = blk_dread(mmc_get_blk_desc(mmc), MINIBOOT_MMC_SECTOR_OFFSET, MINIBOOT_SECTOR_COUNT, MINIBOOT_LOAD_ADDR);times = get_timer(times);if (count != MINIBOOT_SECTOR_COUNT){printf("spl: can't read miniboot from mmc;count:%ld\n", count);return -1;}printf("%lu bytes read in %lu ms", count * 512, times);if (times > 0) {puts(" (");print_size(div_u64(count * 512, times) * 1000, "/s");puts(")");}puts("\n");#elsecount = blk_dread(mmc_get_blk_desc(mmc), IMAGE_MMC_SECTOR_OFFSET, 1, ih);count = blk_dread(mmc_get_blk_desc(mmc), IMAGE_MMC_SECTOR_OFFSET, ih->image_size / 512 + 1 , image_desc);count = blk_dread(mmc_get_blk_desc(mmc), DTB_MMC_SECTOR_OFFSET, DTB_SECTOR_COUNT, DTB_LOAD_ADDR);count = blk_dread(mmc_get_blk_desc(mmc), ATF_MMC_SECTOR_OFFSET, ATF_SECTOR_COUNT, ATF_LOAD_ADDR);count = blk_dread(mmc_get_blk_desc(mmc), MINIBOOT_MMC_SECTOR_OFFSET, MINIBOOT_SECTOR_COUNT, MINIBOOT_LOAD_ADDR);#endifop->ep = (ulong)image_desc;op->dp = (ulong)dtb_desc;return booti_verify(op);}void boot_linux_form_spl(void){int err;struct spl_boot_opr opr;typedef void __noreturn (*image_entry_noargs_t)(void);image_entry_noargs_t image_entry = (image_entry_noargs_t)ATF_LOAD_ADDR;//读取,验证err = read_image(&opr);if (err < 0){printf("read_image error:%d\ncomtinue to run spl\n",err);}else{printf("prepare to jump linux: 0x%p\n", ATF_LOAD_ADDR);image_entry();}}/*------------------------------------------------------------------------------------------------*/void board_init_r(gd_t *dummy1, ulong dummy2){…#ifdef CONFIG_SPL_BOARD_INITspl_board_init();#endif/* 准备kernel启动环境 */boot_linux_form_spl();…}

第二部分 用来代替u-boot的miniboot

1、跳转指令

.text.global _start_start:movx0, #0x43000000movx1, #0movx2, #0movx3, #0movx4, #0x40480000movx5, #0x00000001br x4

2、连接脚本

OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")OUTPUT_ARCH(aarch64)ENTRY(_start)SECTIONS {. = 0x40200000;.text : { *(.text) }. = ALIGN(4);.rodata : {*(.rodata*)} . = ALIGN(4);.data : { *(.data) }. = ALIGN(4);__bss_start = .;.bss : { *(.bss) *(COMMON) }__bss_end = .;}

3、Makefile

CFLAGS := -Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestandingCPPFLAGS := objs := start.ou-boot.bin: $(objs)${LD} -Tboot.lds -o boot.elf $^${OBJCOPY} -O binary -S boot.elf $@${OBJDUMP} -D -m arm boot.elf > boot.dis%.o:%.c${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<%.o:%.S${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<clean:rm -f *.o *.bin *.elf *.dis

4、编译过程

$ source /opt/fsl-imx-x11/4.9.51-mx8-beta/environment-setup-aarch64-poky-linux$ makeaarch64-poky-linux-gcc --sysroot=/opt/fsl-imx-x11/4.9.51-mx8-beta/sysroots/aarch64-poky-linux -Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -c -o start.o start.Saarch64-poky-linux-ld --sysroot=/opt/fsl-imx-x11/4.9.51-mx8-beta/sysroots/aarch64-poky-linux -Tboot.lds -o boot.elf start.oaarch64-poky-linux-objcopy -O binary -S boot.elf u-boot.binaarch64-poky-linux-objdump -D -m arm boot.elf > boot.dis

如果觉得《imx8mq-evk快速启动-bootloader时间优化(eMMC启动)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。