1、uboot引导总体流程
当u-boot监听到用户没有按下键盘等待时间超时后会调用getenv("bootcmd");函数获取bootcmd环境变量的值并执行。u-boot环境变量的值如下图所示:
从图中可以看出bootcmd环境变量其实是完成了六项功能。在这六项功能里最要的是以下四项功能:
run get_boot_sector:用户获取内核所在分区。
run get_images_mmc:从正确的分区中读取内核和设备树到内存中
run set_bootargs:给linux内核传递参数
booti $kernel_addr $ramfs_addr $fdt_addr :booti 命令引导linux内核
u-boot 的核心功能之一是实现了各种命令。这些命令由连接脚本统一定义到u_boot_list段中。每当用户输入命令后,u-boot会从u_boot_list段中查找对应的命令,并执行命令所以对应的函数。例如引导arm64 linux内核的命令booti 定义如下:
从上图中可以看出booti所对应的执行函数为do_booti。在该函数中完成了linux内核的引导。do_booti 函数的实现如下图所以:
在引导linux内核中最重要的一个全局的数据结构是images。该数据结构如下图所示:
其中几个重要的域:
image_info_t os; 内核镜像的一些基本信息,包括内核是否压缩,内核的加载地址,以及内核的类型等等。
ulong ep; 内核镜像的入口地址。
ulong rd_start, rd_end;/* ramdisk 起始和结束地址 */
char *ft_addr; 设备树的地址。
从do_booti函数中可以看出该函数首先调用booti_start(cmdtp, flag, argc, argv, &images)函数。此函数的作用是完成引导之前的一些初始化。其中最重要的一项工作是重定位内核地址。并将重定位后的地址赋值给images->ep域。然后查找设备树的地址和ramdisk的地址并赋值给相应的images结构中的域。
在完成引导前一些初始化后。do_booti调用do_bootm_states函数。该函数的实现如下图所示:
该函数主要作用根据引导的状态作相应的引导操作。然后查找根据images->os域中的操作系统类型去操作系统引导函数表中查找对应的内核引导函数。然后调用相应函数的引导函数。例如linux内核的引导函数为do_bootm_linux其具体实现如下图所示:
在该函数中主要对引导linux内核之前进行配置。然后调用boot_jump_linux(images, flag);函数。boot_jump_linux函数的实现如下图所示:
boot_jump_linux函数定义了一个kernel_entry函数指针。并将linux内核的入口地址赋值给kernel_entry然后,调用kernel_entry函数指针跳到内核的入口地址启动linux内核。至此u-boot引导linux内核完成。u-boot在启动过程中所使用的全部资源包括u-boot所占用的内存会被linux内核全部释放掉。