Uboot启动Linux内核过程简介
前言
如果uboot倒计时结束前没有按下任何按键,main_loop函数将运行到autoboot_command(s) , 该函数里将调用 run_command_list函数,此函数会执行参数 s 指定的一系列命令,也就是环境变量 bootcmd 的命令,bootcmd 里面保存着默认的启动命令。
bootm命令的执行函数为 do_bootm,定义在文件 cmd/bootm.c 中。该函数内解析bootm命令参数,检查是否有子命令(通常没有)。之后调用do_bootm_states 函数来执行不同的 BOOT 阶段,这里要执行的BOOT 阶段有:
BOOTM_STATE_START、
BOOTM_STATE_FINDOS、
BOOTM_STATE_FINDOTHER、
BOOTM_STATE_LOADOS 、
BOOTM_STATE_RAMDISK 、
BOOTM_STATE_OS_PREP 、
BOOTM_STATE_OS_FAKE_GO
和BOOTM_STATE_OS_GO。
第一阶段 BOOTM_STATE_START
运行 bootm_start 函数,函数在 common/bootm.c 文件里
- 主要清空了image结构体。
- 获取uboot的环境变量verify的值并赋给image结构体的verify成员。
- 执行 bootstage_mark_name 函数,主要是记录启动阶段的名字。
- 设置 images 的阶段为BOOTM_STATE_START。
第二阶段 BOOTM_STATE_FINDOS
运行bootm_find_os 函数,函数在 common/bootm.c 文件里。该阶段主要工作是解析 image,获取一些基 本参数信息赋值到 images 全局结构体中。
- boot_get_kernel根据bootm传递的参数获取uImage的储存地址,并调用image_get_kernel 函数进行 kernel 格式校验,输出相关信息
- 获取到内核镜像以后,将镜像的起始地址赋值给参数os_data,镜像的长度赋值给参数os_len。 最后将镜像头部拷贝到 images 的 legacy_hdr_os_copy 成员中,并且设置 legacy_hdr_valid 成员
为 1。 - 使用 genimg_get_format 函数检查镜像类型
- 使用 image_get_XXXX 相关的函数去获取 image 的 type(内核的类型)、comp (内核压缩方式)、os(内核是什么操作系统)、end、load(加载地址)和 arch(芯片架构),然后将其这些信息赋值给 images 的对应成员变量。
- 把内核的起始地址赋值给全局变量 images.os.start
第三阶段 BOOTM_STATE_FINDOTHER
运行 bootm_find_other 函数,函数在 common/bootm.c 文件里。
- 调用 boot_get_ramdisk 函数来获取 ramdisk,对于stm32mp157无效。
- 调用boot_get_fdt函数来获取设备树,并且将设备树首地址赋值给images的ft_addr 成员。
第四阶段 BOOTM_STATE_LOADOS
先 使用 bootm_disable_interrupts 函数禁用中断,再运行 bootm_load_os 函数。主要内容为调用 image_decomp 函数来解压内核。函数的参数都是在第二阶段里获取到参 数 os.image_start = 0Xc2000000 和 load_buf = 0xc2000040,os.image_start 是内核未解压时所在的地址,load_buf是内核的启动地址也就是解压后内核所在的地址。
5、第五阶段 BOOTM_STATE_RAMDISK
通过函数 bootm_os_get_boot_func 来查找系统启动 函数,参数 images->os.os 就是系统类型,根据这个系统类型来选择对应的启动函数。此函数定义 在文件 common/bootm_os.c 中
第六阶段 BOOTM_STATE_PREP
主要是解析bootargs 环境变量和设置内核的启动参数。
第七阶段 BOOTM_STATE_FAKE_GO
代码不执行
第八阶段 BOOTM_STATE_OS_GO
运 行 bootm_selected_os 函数,执行 boot_fn,也就是 do_bootm_linux 函数。第六阶段和第八阶段都会调用do_bootm_linux 函数,但第六阶段传进的 flag 为 BOOTM_STATE_PREP,就会运行boot_prep_linux 函数就是负责解析 bootargs 变量。
第八阶段传进的 fiag 为BOOTM_STATE_OS_GO,就会运行 boot_jump_linux 函数,此函数定义在文件
arch/arm/lib/bootm.c 中