I.MX6 u-boot.imx中IVT、DCD等头部数据的生成

IVT、Boot Data structures、DCD是I.MX6启动时的重要数据和配置。IVT中包含Boot Data structures、DCD地址定位的信息。
BOOT ROM 根据这些地址定位找到DCD的存储位置,使用DCD中的配置参数,来初始化DDR,配置时钟,以及其他启动时必要的硬件设置。
Boot Data structures中包含数据拷贝的目标地址和长度, BOOT ROM会在必要的检查和上述的初始化之后,将启动设备中的数据拷贝
到该目标地址中(通常是DDR),然后跳转到IVT中的entry执行程序镜像。
以下的分析中,我们忽略CSF的使用,CSF只用在High Assurance Boot中,有兴趣可参见I.MX6参考手册中的相关描述。
1. I.MX6 BOOT ROM启动流程中IVT、DCD等 相关 数据操作
当我们选择从SPI FLASH启动时,BOOT ROM会拷贝启动设备SPI FLASH中的前4K bytes数据到片内RAM(OCRAM)。
这初始的4K数据中必须包含IVT(Image vector table)、DCD(Device configuration data)和Boot Data structures,
但由于使用SPI FLASH启动时,IVT的偏移为1K,所以,可以说剩余的3K数据中必须包含IVT、DCD和Boot Data structures。
另外DCD最大长度限制为1768 bytes。
BOOT ROM拷贝SPI FLASH 4K的数据到内部RAM(OCRAM)中去,这4K的空间包含1K的空余头(通常内含分区表)和内含IVT、DCD的数据块。
接着BOOT ROM检查OCRAM 4K数据中包含的IVT头标志0xD1,然后执行DCD检查。这些检查无误通过后,从boot data structure 中解析出
下一步拷贝的目的地址和长度(记为length),然后从SPI FLASH地址0,拷贝长度length的数据到上面解析出的目的地址处。
这里有一个如何在OCRAM中定位boot data structure地址的问题。我们编译生成的u-boot.imx,它的boot data内容即为boot data structure
的地址,而该地址是一个绝对地址,实际为DDR地址,而OCRAM中此时的地址还是原始数据中的该地址。由于此时DDR还未准备好,还未执行
u-boot.imx到DDR的拷贝,BOOT ROM不能使用boot data中的绝对(DDR地址)地址来定位boot data structure。而只能使用偏移地址在
OCRAM中定位boot data structure。   
注意IVT中还有一个self表项,它指向它自身,即IVT的首地址。比如hexdump出u-boot.imx的self的值为0x177ff400,boot_data的值为
0x177ff420,那么boot data structure的地址偏移为
boot data structure  offset = boot_data - self(IVT首地址) = 0x20,
加载到OCRAM中后,boot data structure的有效地址为:OCRAM IVT 加载首地址 + boot data structure  offset,
DCD数据的地址也是如此计算的。
上述过程用C语言伪码描述为:
#define  BOOT_ROM_COPY_DATA_LEN 0x1000  /×4 K bytes */
#define  IVT_OFFSET  0x400
typedefstruct{
    uint8_t tag;
    uint16_t length;
    uint8_t version;
}ivt_header_t;
typedefstruct{
    ivt_header_t header;
   uint32_tentry;
   uint32_treserved1;
   uint32_tdcd_ptr;
   uint32_tboot_data_ptr;
   uint32_tself;
   uint32_tcsf;
   uint32_treserved2;
} ivt_t;
typedefstruct{
   uint32_tstart;
   uint32_tsize;
   uint32_tplugin;
}boot_data_t;

uint32_t *ocram_load_ptr;
ivt_header_t*ivt_h;
ivt_t  *ivt;
boot_data_t   *boot_data_ptr;
ocram_load_ptr=malloc(OCRAM,BOOT_ROM_COPY_DATA_LEN);
copy_to_ocram(spi_flash_addr0,BOOT_ROM_COPY_DATA_LEN, ocram_load_ptr);
ivt_h  =(ivt_header_t *)(ocram_load_ptr+ IVT_OFFSET);  
ivt   =(ivt_t*)(ocram_load_ptr+ IVT_OFFSET);  
if(ivt_h->tag!=0xD1){
       trace"invalid ivt head tag";
      return-1;
}

/*DCD有效性检查*/
......
/*调用DCD中的命令,对DDR、时钟等进行配置*/
......
/*DDR已可用*/

boot_data_ptr =(boot_data_t *)(ocram_load_ptr +(ivt->dcd_ptr-ivt->self)); 
copy_to_ddr(boot_data_ptr->start,boot_data_ptr->size,spi_flash_addr0);
jump_to ivt->entry;

执行完boot_data_ptr中地址和长度的数据拷贝后,我们假定u-boot的加载地址为0x17800000,SPI Flash和DDR RAM的内存镜像图如下:




2. 构建系统生成包含IVT、boot Data、DCD等 头部的镜像文件 u-boot.imx
2.1 u-boot-2009.8版本
在u-boot-2009.8中,IVT、boot Data、DCD在汇编文件flash_header.S实现:
ivt_header: .word 0x402000D1 /* Tag=0xD1, Len=0x0020, Ver=0x40 */
app_code_jump_v: .word _start
reserv1: .word 0x0
dcd_ptr: .word dcd_hdr
boot_data_ptr: .word boot_data
self_ptr: .word ivt_header
#ifdef CONFIG_SECURE_BOOT
app_code_csf: .word __hab_data
#else
app_code_csf: .word 0x0
#endif
reserv2: .word 0x0

boot_data: .word TEXT_BASE
#ifdef CONFIG_SECURE_BOOT
image_len: .word __hab_data_end - TEXT_BASE + CONFIG_FLASH_HEADER_OFFSET
#else
image_len: .word _end_of_copy - TEXT_BASE + CONFIG_FLASH_HEADER_OFFSET
#endif
plugin: .word 0x0

dcd_hdr: .word 0x40E001D2 /* DDR cfg Tag=0xD2, Len=59*8 + 4 + 4, Ver=0x40 */


write_dcd_cmd: .word 0x048402CC /* Tag=0xCC, Len=80*8 + 4, Param=0x04 */
/* DCD */

/* DDR3 initialization based on the MX6Solo Auto Reference Design (ARD) */
/* DDR IO TYPE */
MXC_DCD_ITEM(1, IOMUXC_BASE_ADDR + 0x774, 0x000c0000)
MXC_DCD_ITEM(2, IOMUXC_BASE_ADDR + 0x754, 0x00000000)

/* CLOCK */
MXC_DCD_ITEM(3, IOMUXC_BASE_ADDR + 0x4ac, 0x00000030)
MXC_DCD_ITEM(4, IOMUXC_BASE_ADDR + 0x4b0, 0x00000030)
......
上述代码中,部分包含地址的变量和其目标地址的关系图如下:


u-boot构建系统会将此文件编译后,连同u-boot.bin文件链接生成最终的u-boot.imx。
另外,我们看到,上面的ivt_header和dcd_hdr,均是以0x40开头的tag,而i.mx6的用户参考手册reference manual中
该值应为0x41,对此,论坛上有如下解释:
Really i.MX6 is one of HAB 4.1, the mentions about ver. 4.0 are derivative
from i.MX53 and do not influence on HAB functionality. One of main differences
between the ver. 4.1 and ver. 4.0 is ability for the rev. 4.1 to support Encrypted
Boot by ROM.
由于u-boot-2009.8版本已为过时的版本,在此不再多做分析。

2.1 u-boot-2015.07版本
u-boot-2015.07及以后的版本中,更改了u-boot.imx的产生方式,不再使用上述的flash_header.S,
而是使用mkimage工具直接生成。此处使用的mkimage包含的目标文件类型-T参数中新增了imximage选项,
mkimage会调用格式类型imximage的解释器来生成针对i.mx(5系6系)系列芯片的 IVT、boot Data、DCD的格式头。具体的代码
实现在tools/imximage.c中。
我们以boundary的nitrogen6q开发板为例,当构建系统执行:
./tools/mkimage -n board/boundary/nitrogen6x/nitrogen6q.cfg.cfgtmp -T imximage -e 0x17800000 -d u-boot.bin u-boot.imx
 其中-n指明输入文件为nitrogen6q.cfg.cfgtmp,-T指明解释器为imximage,-e为镜像程序入口点。
mkimage调用选项-T的imximage 解释器解析输入文件nitrogen6q.cfg.cfgtmp,而文件nitrogen6q.cfg.cfgtmp为nitrogen6q.cfg编译时
预处理(使用gcc -E选项)后产生的临时文件。nitrogen6q.cfg的内容如下:
/* image version */
IMAGE_VERSION 2

/*
 * Boot Device : one of
 * spi, sd (the board has no nand neither onenand)
 */
BOOT_FROM      spi

#define __ASSEMBLY__
#include <config.h>
#include "asm/arch/mx6-ddr.h"
#include "asm/arch/iomux.h"
#include "asm/arch/crm_regs.h"

#include "ddr-setup.cfg"
#include "1066mhz_4x128mx16.cfg"
#include "clocks.cfg"
注意,其中包含的IMAGE_VERSION 2和BOOT_FROM      spi,它们将在下面会被使用。
该文件预处理后会将ddr-setup.cfg、1066mhz_4x128mx16.cfg、clocks.cfg的内容复制到nitrogen6q.cfg.cfgtmp中,而
前三个文件即为DCD配置文件,如ddr-setup.cfg的内容为:
DATA 4, MX6_IOM_DRAM_SDQS0, 0x00000030
DATA 4, MX6_IOM_DRAM_SDQS1, 0x00000030
DATA 4, MX6_IOM_DRAM_SDQS2, 0x00000030
DATA 4, MX6_IOM_DRAM_SDQS3, 0x00000030
如MX6_IOM_DRAM_SDQS0 又在文件arch/arm/include/asm/arch/mx6q-ddr.h中定义:
#define MX6_IOM_DRAM_SDQS0    0x020e05a8

预处理后为(删除了空行和注解):
IMAGE_VERSION 2
BOOT_FROM spi
DATA4,0x020e05a8,0x00000030
DATA4,0x020e05b0,0x00000030
DATA4,0x020e0524,0x00000030
DATA4,0x020e051c,0x00000030

接下来我们分析imximage.c代码中相关处理:
函数的调用流程为:parse_cfg_file-->parse_cfg_fld-->parse_cfg_cmd-->设置imximage_ivt_offset。
下面我们主要分析配置解析函数parse_cfg_cmd:
statictable_entry_t imximage_boot_offset[]={
    {FLASH_OFFSET_ONENAND,  "onenand",  "OneNAND Flash",},
    {FLASH_OFFSET_NAND, "nand",     "NAND Flash",   },
    {FLASH_OFFSET_NOR,  "nor",      "NOR Flash",    },
    {FLASH_OFFSET_SATA, "sata",     "SATA Disk",    },
    {FLASH_OFFSET_SD,   "sd",       "SD Card",  },
    {FLASH_OFFSET_SPI,  "spi",      "SPI Flash",    },
    {FLASH_OFFSET_QSPI, "qspi",     "QSPI NOR Flash",},
    {-1,            "",     "Invalid",  },
};

staticvoidparse_cfg_cmd(structimx_header*imxhdr,int32_t cmd,char*token,
                char*name,intlineno,intfld,intdcd_len)
{
    intvalue;
    staticintcmd_ver_first=~0;
    switch(cmd){
    caseCMD_IMAGE_VERSION:
        imximage_version=get_cfg_value(token,name,lineno);
              ......
        set_hdr_func();
        break;
    caseCMD_BOOT_FROM:
        imximage_ivt_offset=get_table_entry_id(imximage_boot_offset,
        ......
        break;
    caseCMD_BOOT_OFFSET:
        imximage_ivt_offset=get_cfg_value(token,name,lineno);
        ......
        break;
    ......

    }
}
函数parse_cfg_cmd使用前导函数从输入文件nitrogen6q.cfg.cfgtmp取出的参数,当参数是CMD_IMAGE_VERSION,它对应
nitrogen6q.cfg.cfgtmp文件中的MAGE_VERSION 2,然后调用get_cfg_value得到版本号为2。imximage的头格式分版本号1和2。
同理CMD_BOOT_FROM,对应于nitrogen6q.cfg.cfgtmp文件中的BOOT_FROM   spi,调用get_table_entry_id在
表imximage_boot_offset找到spi对应的偏移量FLASH_OFFSET_SPI(它在文件imximage.h中定义为0x400,这里反映了不同
的启动设备其IVT偏移量的不同)。后续的操作以此为参数,然后联合其他的解析结果,生成总的结构体imx_header_v2_t,
最后mkimage将这个结构体插入文件u-boot.bin的头部,生成u-boot.imx文件。
另外,我们可以在文件imximage.c中的函数print_hdr_v2结尾处增加如下代码,在终端中输出产生的头部信息:
    printf("\n--------------------------------------\n");
    printf("tag:        0x%04x\n", (uint8_t)fhdr_v2->header.tag);
    printf("length:     0x%04x\n", (uint16_t)fhdr_v2->header.length);
    printf("version:    0x%04x\n", (uint8_t)fhdr_v2->header.version);
    
    printf("\n");
    
    printf("entry:         0x%08x\n", (uint32_t)fhdr_v2->entry);
    printf("reserved1:     0x%08x\n", (uint32_t)fhdr_v2->reserved1);
    printf("dcd_ptr:       0x%08x\n", (uint32_t)fhdr_v2->dcd_ptr);
    printf("boot_data_ptr: 0x%08x\n", (uint32_t)fhdr_v2->boot_data_ptr);
    printf("self:          0x%08x\n", (uint32_t)fhdr_v2->self);
    printf("csf:           0x%08x\n", (uint32_t)fhdr_v2->csf);
    printf("reserved2:     0x%08x\n", (uint32_t)fhdr_v2->reserved2);
    printf("\n");
    printf("db start:      0x%08x\n", (uint32_t)db->start);
    printf("db size:       0x%08x\n", (uint32_t)db->size);
    printf("db plugin:     0x%08x\n", (uint32_t)db->plugin);
    printf("--------------------------------------\n\n");

在u-boot源码中重新编译主机程序mkimage:
u-boot$make tools-only
然后单独执行mkimage命令:
u-boot$./tools/mkimage -n board/boundary/nitrogen6x/nitrogen6q.cfg.cfgtmp -T imximage -e 0x17800000 -d u-boot.bin u-boot.imx
相应的输出结果大致如下:
tag:        0x00d1
length:     0x2000   the overall length of the IVT in bytes, including the header. (the length is fixed and must have a value of 32 bytes),8K????
version:    0x0040

entry:          0x17800000
reserved1:      0x00000000
dcd_ptr:        0x177ff42c     
boot_data_ptr:  0x177ff420
self:           0x177ff400      
csf:            0x00000000
reserved2:      0x00000000

db start:       0x177ff000
db size:        0x00075000    
db plugin:      0x00000000





  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
i.MX6U SPL和u-boot是嵌入式系统的两个重要组件,用于启动ARM架构的i.MX6U处理器。SPL(Secondary Program Loader)是首先加载到处理器的一段代码,其主要功能是初始化内存控制器和一些必要的外设,然后通过加载u-boot来完成系统的启动。 SPL可以理解为一个小型的操作系统,其大小通常在几十到几百KB之间,由于其能力有限,因此只能完成初始化和加载u-boot的任务。SPL会配置处理器的时钟、内存和外设等硬件资源,以便后续的操作系统能够正常运行。在i.MX6U处理器上,SPL还可以提供一些额外的功能,如从网络或外部存储设备加载u-bootu-boot是一个开源的引导加载器,在ARM嵌入式系统广泛应用。它负责加载操作系统内核和文件系统,并提供丰富的命令行接口,用于系统的配置和调试。u-boot可以通过串口、网络和外部存储设备等多种方式进行通信,从而实现系统的启动和调试。 i.MX6U SPL和u-boot常常一起使用,以实现系统的启动和初始化。首先,SPL会被加载到处理器的内存,并执行初始化操作和加载u-boot。接下来,u-boot会被加载到内存,并根据配置文件的设置启动操作系统或加载文件系统。 总结来说,i.MX6U SPL和u-boot是i.MX6U处理器启动过程不可或缺的两个组件,其SPL负责初始化和加载u-boot,而u-boot则负责加载操作系统和提供系统配置和调试的功能。这两个组件的协同工作确保了i.MX6U处理器能够正常启动和运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值