这篇博客主要分析 init_sequence_f 函数指针数组中的fdtdec_setup函数:
#ifdef CONFIG_OF_CONTROL //在.config中CONFIG_OF_CONTROL=y
fdtdec_setup,
#endif
int fdtdec_setup(void)
{
#if CONFIG_IS_ENABLED(OF_CONTROL) //在.config中CONFIG_OF_CONTROL=y
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT) //在.config中CONFIG_MULTI_DTB_FIT未定义
void *fdt_blob;
# endif
# ifdef CONFIG_OF_EMBED //在.config中CONFIG_OF_EMBED未定义
# ifdef CONFIG_SPL_BUILD
gd->fdt_blob = __dtb_dt_spl_begin;
# else
gd->fdt_blob = __dtb_dt_begin;
# endif
# elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
//在.config中CONFIG_OF_BOARD未定义,CONFIG_OF_SEPARATE=y
gd->fdt_blob = board_fdt_blob_setup();
__weak void *board_fdt_blob_setup(void)
{
void *fdt_blob = NULL;
#ifdef CONFIG_SPL_BUILD
if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))
fdt_blob = (ulong *)&_image_binary_end;
else
fdt_blob = (ulong *)&__bss_end;
#else
fdt_blob = (ulong *)&_end;
#endif
return fdt_blob;
}
//gd->fdt_blob=(ulong *)&_end;
# elif defined(CONFIG_OF_HOSTFILE)
if (sandbox_read_fdt_from_file()) {
puts("Failed to read control FDT\n");
return -1;
}
# endif
# ifndef CONFIG_SPL_BUILD
# if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) //CONFIG_OF_PRIOR_STAGE在.config中设为未定义
gd->fdt_blob = (void *)prior_stage_fdt_address;
# else
gd->fdt_blob = map_sysmem(env_get_ulong("fdtcontroladdr", 16,(unsigned long)map_to_sysmem(gd->fdt_blob)), 0);
static inline phys_addr_t map_to_sysmem(const void *ptr)
{
return (phys_addr_t)(uintptr_t)ptr; //typedef unsigned long long phys_addr_t
}
//env_get_ulong的第三个参数default_val=gd->fdt_blob=&_end
ulong env_get_ulong(const char *name, int base, ulong default_val)
{
const char *str = env_get(name); //根据传入的fdtcontroladdr调用env_get查询变量值
char *env_get(const char *name)
{
if (gd->flags & GD_FLG_ENV_READY) { //gd->flags=0
ENTRY e, *ep;
WATCHDOG_RESET();
e.key = name;
e.data = NULL;
hsearch_r(e, FIND, &ep, &env_htab, 0);
return ep ? ep->data : NULL;
}
if (env_get_f(name, (char *)(gd->env_buf), sizeof(gd->env_buf)) > 0)
return (char *)(gd->env_buf);
return NULL;
}
//env_get调用env_get_f来查询fdtcontroladdr环境变量值
int env_get_f(const char *name, char *buf, unsigned len)
{
int i, nxt, c;
for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
//env_get_char(i)等价于default_environment[i]
int val, n;
for (nxt = i; (c = env_get_char(nxt)) != '\0'; ++nxt) {
if (c < 0)
return c;
if (nxt >= CONFIG_ENV_SIZE)
return -1;
}
val = envmatch((uchar *)name, i);
//从default_environment中查询匹配name(fdtcontroladdr)的变量
static char default_environment[] = {
"bootcmd=" CONFIG_BOOTCOMMAND "\0"
"bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0"
"baudrate=" __stringify(CONFIG_BAUDRATE) "\0"
"loadaddr=" __stringify(CONFIG_LOADADDR) "\0"
"script=boot.scr\0" \
"image=Image\0" \
"panel=NULL\0" \
"console=ttyLP0,${baudrate} earlycon=lpuart32,0x5a060000,${baudrate}\0" \
"fdt_addr=0x83000000\0" \
"fdt_high=0xffffffffffffffff\0" \
"boot_fdt=try\0" \
"fdt_file=fsl-imx8qxp-mek.dtb\0" \
"initrd_addr=0x83800000\0" \
"initrd_high=0xffffffffffffffff\0" \
"mmcdev="__stringify(CONFIG_SYS_MMC_ENV_DEV)"\0" \
"mmcpart=" __stringify(CONFIG_SYS_MMC_IMG_LOAD_PART) "\0" \
"mmcroot=" CONFIG_MMCROOT " rootwait rw\0" \
"mmcautodetect=yes\0" \
"mmcargs=setenv bootargs console=${console} root=${mmcroot}\0 " \
"loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};\0" \
"bootscript=echo Running bootscript from mmc ...; " \
"source\0" \
"loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}\0" \
"loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}\0" \
"mmcboot=echo Booting from mmc ...; " \
"run mmcargs; " \
"if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \
"if run loadfdt; then " \
"booti ${loadaddr} - ${fdt_addr}; " \
"else " \
"echo WARN: Cannot load the DT; " \
"fi; " \
"else " \
"echo wait for boot; " \
"fi;\0" \
"netargs=setenv bootargs console=${console} " \
"root=/dev/nfs " \
"ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp\0" \
"netboot=echo Booting from net ...; " \
"run netargs; " \
"if test ${ip_dyn} = yes; then " \
"setenv get_cmd dhcp; " \
"else " \
"setenv get_cmd tftp; " \
"fi; " \
"${get_cmd} ${loadaddr} ${image}; " \
"if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \
"if ${get_cmd} ${fdt_addr} ${fdt_file}; then " \
"booti ${loadaddr} - ${fdt_addr}; " \
"else " \
"echo WARN: Cannot load the DT; " \
"fi; " \
"else " \
"booti; " \
"fi;\0"
"\0"
}
//在default_environment中没有fdtcontroladdr参数
if (val < 0)
continue;
for (n = 0; n < len; ++n, ++buf) {
c = env_get_char(val++);
if (c < 0)
return c;
*buf = c;
if (*buf == '\0')
return n;
}
if (n)
*--buf = '\0';
printf("env_buf [%u bytes] too small for value of \"%s\"\n",len, name);
return n;
}
return -1;
}
//env_get_f返回-1,则env_get返回NULL,即str=NULL
return str ? simple_strtoul(str, NULL, base) : default_val;
}
//env_get_ulong返回默认值default_val=gd->fdt_blob=&_end
static inline void *map_sysmem(phys_addr_t paddr, unsigned long len)
{
return (void *)(uintptr_t)paddr; //typedef unsigned long int uintptr_t
}
//最终gd->fdt_blob=&_end
# endif
# endif
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT) //CONFIG_MULTI_DTB_FIT在.config中设置为未定义
if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0)
gd->fdt_blob = fdt_blob;
fdt_blob = locate_dtb_in_fit(gd->fdt_blob);
if (fdt_blob) {
gd->multi_dtb_fit = gd->fdt_blob;
gd->fdt_blob = fdt_blob;
}
# endif
#endif
return fdtdec_prepare_fdt(); //检查在gd->fdt_blob处是否存在dtb
}
通过本文的分析,我们知道dtb文件放在&_end处,_end在链接文件定义。
fdtdec_setup的作用就是讲dtb文件的地址放入gd->fdt_blob处