参考资料来源: https://www.bilibili.com/video/BV12E411h71h?p=22&vd_source=432ba293ecfc949a4174ab91ccc526d6 正点原子Linux驱动开发指南
image全局变量:
在bootm.c中,存在一个全局变量bootm_headers_t images; /* pointers to os/initrd/fdt images */结构体定义如下:
image全局变量: 在bootm.c中,存在一个全局变量 bootm_headers_t images; /* pointers to os/initrd/fdt images */ 结构体定义如下: typedef struct image_info { ulong start, end; /* start/end of blob */ ulong image_start, image_len; /* start of image within blob, len of image */ ulong load; /* load addr for the image */ uint8_t comp, type, os; /* compression, type of image, os type */ uint8_t arch; /* CPU architecture */ } image_info_t; /* * Legacy and FIT format headers used by do_bootm() and do_bootm_<os>() * routines. */ typedef struct bootm_headers { /* * Legacy os image header, if it is a multi component image * then boot_get_ramdisk() and get_fdt() will attempt to get * data from second and third component accordingly. */ image_header_t *legacy_hdr_os; /* image header pointer */ image_header_t legacy_hdr_os_copy; /* header copy */ ulong legacy_hdr_valid; #if defined(CONFIG_FIT) const char *fit_uname_cfg; /* configuration node unit name */ void *fit_hdr_os; /* os FIT image header */ const char *fit_uname_os; /* os subimage node unit name */ int fit_noffset_os; /* os subimage node offset */ void *fit_hdr_rd; /* init ramdisk FIT image header */ const char *fit_uname_rd; /* init ramdisk subimage node unit name */ int fit_noffset_rd; /* init ramdisk subimage node offset */ void *fit_hdr_fdt; /* FDT blob FIT image header */ const char *fit_uname_fdt; /* FDT blob subimage node unit name */ int fit_noffset_fdt;/* FDT blob subimage node offset */ void *fit_hdr_setup; /* x86 setup FIT image header */ const char *fit_uname_setup; /* x86 setup subimage node name */ int fit_noffset_setup;/* x86 setup subimage node offset */ #endif #ifndef USE_HOSTCC image_info_t os; /* os image info */ ulong ep; /* entry point of OS */ ulong rd_start, rd_end;/* ramdisk start/end */ char *ft_addr; /* flat dev tree address */ ulong ft_len; /* length of flat device tree */ ulong initrd_start; ulong initrd_end; ulong cmdline_start; ulong cmdline_end; bd_t *kbd; #endif int verify; /* getenv("verify")[0] != 'n' */ #define BOOTM_STATE_START (0x00000001) #define BOOTM_STATE_FINDOS (0x00000002) #define BOOTM_STATE_FINDOTHER (0x00000004) #define BOOTM_STATE_LOADOS (0x00000008) #define BOOTM_STATE_RAMDISK (0x00000010) #define BOOTM_STATE_FDT (0x00000020) #define BOOTM_STATE_OS_CMDLINE (0x00000040) #define BOOTM_STATE_OS_BD_T (0x00000080) #define BOOTM_STATE_OS_PREP (0x00000100) #define BOOTM_STATE_OS_FAKE_GO (0x00000200) /* 'Almost' run the OS */ #define BOOTM_STATE_OS_GO (0x00000400) int state; #ifdef CONFIG_LMB struct lmb lmb; /* for memory mgmt */ #endif } bootm_headers_t;imx6ull的zImage地址0x80800000,dtb地址为0x83000000
bootz命令的执行流程:
int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int ret; /* Consume 'bootz' */ argc--; argv++; if (bootz_start(cmdtp, flag, argc, argv, &images)) return 1; /* * We are doing the BOOTM_STATE_LOADOS state ourselves, so must * disable interrupts ourselves */ bootm_disable_interrupts(); images.os.os = IH_OS_LINUX; ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO, &images, 1); return ret; }bootz执行流程:
bootz ->bootz_start ->do_bootm_states ->执行BOOTM_STATE_START阶段 ->bootm_start 对images全局变量清零 ->images->ep = 0x80800000 ->bootz_setup 判断zImage是否符合要求 ->bootm_find_images ->boot_get_fdt 找到设备树,然后将设备树起始地址和长度,写入到images的ft_addr和ft_len成员变量中 ->bootm_disable_interrupts 关闭中断 ->do_bootm_states 根据不同的BOOT状态执行不同的代码段 ->bootm_os_get_boot_func 查找linux启动函数。找到linux内核启动函数,赋值给boot_fn ->do_bootm_linux ->boot_prep_linux 启动之前的一些工作,bootargs传给linux kernel ->boot_jump_linux ->announce_and_cleanup Starting kernel ->kernel_entry 调用zImage里面的0x80800000处的函数
boot_jump_linux函数:
static void boot_jump_linux(bootm_headers_t *images, int flag) { ... if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) { // 使用设备树 r0 = 2; r2 = (unsigned int)images->ft_addr; } else { r0 = 1; r2 = (unsigned int)getenv("bootargs"); } smp_set_core_boot_addr((unsigned long)kernel_entry, -1); smp_kick_all_cpus(); if (!fake) kernel_entry(r0, 0, r2); // 使用设备树的情况下,r2表示设备树的起始地址 ... }