Uboot源码超详细分析(2)
目录
一.bootz启动linux内核过程
1.images全局变量
2.bootz函数
3.bootz_start 函数
4.do_bootm_states函数
5.bootm_os_get_boot_func 函数
6.do_bootm_linux 函数
一.bootz启动linux内核过程
1.images全局变量
不管是 bootz 还是 bootm 命令,在启动 Linux 内核的时候都会用到一个重要的全局变量:images,images 在文件 cmd/bootm.c 中有如下定义:
bootm_headers_t images;
bootm_headers_t结构体中的相关变量有:
image_info_t os; /* OS 镜像信息 */
ulong /* OS 入口点 */
ulong rd_start, rd_end; /* ramdisk 开始和结束位置 */
char *ft_addr; /* 设备树地址 */
ulong ft_len; /* 设备树长度 */
ulong initrd_start; /* initrd 开始位置 */
ulong initrd_end; /* initrd 结束位置 */
ulong cmdline_start; /* cmdline 开始位置 */
ulong cmdline_end;
bd_t *kbd; /* cmdline 结束位置 *///宏定义表示 BOOT 的不同阶段
#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)
其中os 成员变量是image_info_t类型的,为系统镜像信息。image_info_t定义如下:
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;
2.bootz函数
bootz 命令的执行函数为 do_bootz,在文件 cmd/bootm.c 中有如下定义:
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_start 函数,调用函数 bootm_disable_interrupts 关闭中断。设置 images.os.os 为 IH_OS_LINUX,也就是设置系统镜像为 Linux。调用函数 do_bootm_states 来执行不同的 BOOT 阶段,这里要执行的 BOOT 阶段有: BOOTM_STATE_OS_PREP 、 BOOTM_STATE_OS_FAKE_GO 和 BOOTM_STATE_OS_GO。
3.bootz_start 函数
bootz_srart 函数也定义在文件 cmd/bootm.c 中,bootz_start 主要用于初始化 images 的相关成员变量,函数内容如下:
static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,char * const argv[], bootm_headers_t *images)
{int ret;ulong zi_start, zi_end;//调用函数 do_bootm_states,执行 BOOTM_STATE_START 阶段。ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,images, 1);/* Setup Linux kernel zImage entry point *///设置 images 的 ep 成员变量,也就是系统镜像的入口点if (!argc) {images->ep = load_addr;debug("* kernel: default image load address = 0x%08lx\n",load_addr);} else {images->ep = simple_strtoul(argv[0], NULL, 16);debug("* kernel: cmdline image address = 0x%08lx\n",images->ep);}//调用 bootz_setup 函数,判断当前的系统镜像文件是否为Linux的镜像文件ret = bootz_setup(images->ep, &zi_start, &zi_end);if (ret != 0)return 1;lmb_reserve(&images->lmb, images->ep, zi_end - zi_start);//查找 ramdisk 和设备树(dtb)文件if (bootm_find_images(flag, argc, argv))return 1;#ifdef CONFIG_SECURE_BOOTextern uint32_t authenticate_image(uint32_t ddr_start, uint32_t image_size);if (authenticate_image(images->ep, zi_end - zi_start) == 0) {printf("Authenticate zImage Fail, Please check\n");return 1;}
#endifreturn 0;
}
4.do_bootm_states函数
do_bootz 最 后 调 用 的 就 是 函 数 do_bootm_states , 而 且 在 bootz_start 中 也 调 用 了
do_bootm_states 函 数 ,此 函 数 定 义 在 文 件common/bootm.c 中。
函数 do_bootm_states 根据不同的 BOOT 状态执行不同的代码段,通过如下代码来判断
BOOT 状态:
states & BOOTM_STATE_XXX
通过函数 bootm_os_get_boot_func 来查找系统启动函数,参数 images->os.os 是系统类型,根据这个系统类型选择对应的启动函数,在 do_bootz 中设置images.os.os=IH_OS_LINUX。函数返回值就是找到的系统启动函数,这里找到的 Linux 系统启动函数为 do_bootm_linux,因此 boot_fn=do_bootm_linux,后面执行 boot_fn函数的地方实际上是执行的 do_bootm_linux 函数。
调用函数 boot_selected_os 启动 Linux 内核,此函数第 4 个参数为 Linux 系统镜
像头,第 5 个参数就是 Linux 系统启动函数 do_bootm_linux。
5.bootm_os_get_boot_func 函数
查找对应系统的启动函数,此函数定义在文件 common/bootm_os.c 中。
6.do_bootm_linux 函数
do_bootm_linux 就是最终启动 Linux 内核的函数,此函数定义在文件 arch/arm/lib/bootm.c,函数内容如下:
int do_bootm_linux(int flag, int argc, char * const argv[],bootm_headers_t *images)
{/* No need for those on ARM */if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)return -1;if (flag & BOOTM_STATE_OS_PREP) {boot_prep_linux(images);return 0;}if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {boot_jump_linux(images, flag);return 0;}boot_prep_linux(images);boot_jump_linux(images, flag);return 0;
}
在do_bootm_linux函数中调用boot_prep_linux函数,此函数的作用是在启动linux之前做一些其他处理,比如在设备树的chosen节点下添加子结点bootargs,bootargs子结点存放bootargs环境变量。
在boot_jump_linux函数中调用announce_and_cleanup函数输出starting kernel ...并且做一些清理工作,调用kernel_entry函数启动linux内核。