首页 > 其他分享 >uboot-5_bootm/bootz启动内核过程

uboot-5_bootm/bootz启动内核过程

时间:2024-01-15 17:00:31浏览次数:27  
标签:BOOTM uboot bootz image bootm STATE Linux os

1 images 全局变量

不管是 bootz 还是 bootm 命令,启动kernel都会用到images全局变量。images 定义在文件 cmd/bootm.c:
image
include/image.h 中的定义了bootm_headers_t结构:该结构描述的是bootm启动时的头部信息。该结构又包含了系统镜像头部和系统镜像。

1.1 bootm头部结构

304 typedef struct bootm_headers {
305 	/*
306 	* Legacy os image header, if it is a multi component image
307 	* then boot_get_ramdisk() and get_fdt() will attempt to get
308 	* data from second and third component accordingly.
309 	*/
310 	image_header_t *legacy_hdr_os; /* image header pointer */
311 	image_header_t legacy_hdr_os_copy; /* header copy */
312 	ulong legacy_hdr_valid;
313
......
333
334 	#ifndef USE_HOSTCC
335 	image_info_t os; /* OS 镜像信息 */
336 	ulong ep; /* OS 入口点 */
337
338 	ulong rd_start, rd_end; /* ramdisk 开始和结束位置 */
339
340 	char *ft_addr; /* 设备树地址 */
341 	ulong ft_len; /* 设备树长度 */
342
343 	ulong initrd_start; /* initrd 开始位置 */ 
344 	ulong initrd_end; /* initrd 结束位置 */
345 	ulong cmdline_start; /* cmdline 开始位置 */
346 	ulong cmdline_end; /* cmdline 结束位置 */
347 	bd_t *kbd;
348 #endif
349
350 	int verify; /* getenv("verify")[0] != 'n' */
351
352 	#define BOOTM_STATE_START (0x00000001)
353 	#define BOOTM_STATE_FINDOS (0x00000002)
354 	#define BOOTM_STATE_FINDOTHER (0x00000004)
355 	#define BOOTM_STATE_LOADOS (0x00000008)
356 	#define BOOTM_STATE_RAMDISK (0x00000010)
357 	#define BOOTM_STATE_FDT (0x00000020)
358 	#define BOOTM_STATE_OS_CMDLINE (0x00000040)
359 	#define BOOTM_STATE_OS_BD_T (0x00000080)
360 	#define BOOTM_STATE_OS_PREP (0x00000100)
361 	#define BOOTM_STATE_OS_FAKE_GO (0x00000200)/*'Almost' run the OS*/
362 	#define BOOTM_STATE_OS_GO (0x00000400)
363 	int state;
364
365 	#ifdef CONFIG_LMB
366 	struct lmb lmb; /* 内存管理相关,不深入研究 */
367 #endif
368 } bootm_headers_t;

第 352~362 行这 11 个宏定义表示 BOOT 的不同阶段。

1.1.1 系统镜像头部结构

先来看下image_header_t结构,也就是系统镜像头部信息:
image

typedef struct image_header {
	__be32		ih_magic;	/* Image Header Magic Number	*/
	__be32		ih_hcrc;	/* Image Header CRC Checksum	*/
	__be32		ih_time;	/* Image Creation Timestamp	*/
	__be32		ih_size;	/* Image Data Size		*/
	__be32		ih_load;	/* Data	 Load  Address		*/
	__be32		ih_ep;		/* Entry Point Address		*/
	__be32		ih_dcrc;	/* Image Data CRC Checksum	*/
	uint8_t		ih_os;		/* Operating System		*/
	uint8_t		ih_arch;	/* CPU architecture		*/
	uint8_t		ih_type;	/* Image Type			*/
	uint8_t		ih_comp;	/* Compression Type		*/
	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
} image_header_t;

1.1.2 系统镜像结构

再来看下image_info_t结构,也就是系统镜像信息结构:
image

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 do_bootz 函数

do_bootz 函数定义在cmd/bootm.c:
image
先执行bootz_start。先执行BOOTM_STATE_START 阶段。
第 638 行,设置 images.os.os 为 IH_OS_LINUX,也就是设置系统镜像为 Linux,表示我们要启动的是 Linux 系统!后面会用到 images.os.os 来挑选具体的启动函数。
第 639 行,调用函数 do_bootm_states 来执行不同的 BOOT 阶段,这里要执行的 BOOT 阶段有:BOOTM_STATE_OS_PREP 、BOOTM_STATE_OS_FAKE_GO 和BOOTM_STATE_OS_GO。

2.1 bootz_start

image

  1. 调用函数 do_bootm_states,执行 BOOTM_STATE_START 阶段。
  2. 593 行,设置 images 的 ep,也就是系统镜像的入口点,使用 bootz 命令启动系统的时候就会设置系统在 DRAM 中的存储位置,这个存储位置就是系统镜像的入口点,因此 images->ep=0X80800000。
  3. 调用 bootz_setup 函数,此函数会判断当前的系统镜像文件是否为 Linux 的镜像文件,并且会打印出镜像相关信息,bootz_setup 函数稍后会讲解、
  4. 调用 bootm_find_images 查找 ramdisk 和设备树(dtb)文件,但是我们没有用到 ramdisk,因此此函数在这里仅仅用于查找设备树(dtb)文件,此函数稍后也会讲解。

2.1.1 bootm_start

执行 BOOTM_STATE_START 阶段时,执行bootm_start:
image
初始化verfify 成员, 设置images状态为 BOOTM_STATE_START。

2.1.2 bootz_setup

定义在文件 arch/arm/lib/bootm.c:
image

  1. 宏 LINUX_ARM_ZIMAGE_MAGIC 就是 ARM Linux 系统魔术数。
  2. 从传递进来的参数 image(也就是系统镜像首地址)中获取 zimage 头。
  3. 判断 image 是否为 ARM 的 Linux 系统镜像,如果不是的话就直接返回,并且打印出“Bad Linux ARM zImage magic!”,比如我们输入一个错误的启动命令:
    bootz 80000000 – 900000000
    因为我们并没有在 0X80000000 处存放 Linux 镜像文件(zImage),因此上面的命令肯定会执行出错如下:
    image
  4. 初始化函数 bootz_setup 的参数 start 和 end。
  5. 打印启动信息,如果 Linux 系统镜像正常的话打印如下:
    image

2.1.3 bootm_find_images

定义在文件 common/bootm.c:
image

  1. 查找 ramdisk,但是我们没有用到 ramdisk,因此这部分代码不用管。
  2. 查找设备树(dtb)文件,找到以后就将设备树的起始地址和长度分别写到images 的 ft_addr 和 ft_len 成员变量中。我们使用 bootz 启动 Linux 的时候已经指明了设备树在DRAM 中的存储地址,因此 images.ft_addr=0X83000000,长度根据具体的设备树文件而定,比如我现在使用的设备树文件长度为 0X8C81,因此 images.ft_len=0X8C81。

2.2 do_bootm_states

image
前面将state先处理了 BOOTM_STATE_START 阶段,接下来处里下面三个状态:

BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO

2.2.1 bootm_os_get_boot_func

进入第658行,通过bootm_os_get_boot_func来查找系统启动函数。由于前面提到images->os.os 就是系统类型设置 为 IH_OS_LINUX,根据这个os类型来选择对应的启动函数名为do_bootm_linux:
image

2.2.2 boot_pre_linux

第 676-677 行,处理 BOOTM_STATE_OS_PREP 状态,调用函数 do_bootm_linux,do_bootm_linux调用 boot_prep_linux 来完成具体的处理过程。boot_prep_linux 主要用于处理环境变量bootargs,bootargs 保存着传递给 Linux kernel 的参数:
image

设备树的chosen节点下存放了子节点bootargs,bootargs子节点存放bootargs环境变量

2.2.3 boot_jump_linux

第699行,调用函数 boot_selected_os 启动 Linux 内核,此函数第 4 个参数为 Linux 系统镜像头,第 5 个参数就是 Linux 系统启动函数 do_bootm_linux。boot_selected_os 函数定义在文件common/bootm_os.c如下:
image
最终调用 boot_selected_os->boot_fn(即do_bootm_linux)->boot_jump_linux来启动 Linux 内核:
image
boot_jump_linux:
image

  1. 我们的板子IMX6ULL是armv7 32位架构,因此从else开始,第293 行,变量 machid 保存机器 ID,如果不使用设备树的话这个机器 ID 会被传递给 Linux内核,Linux 内核会在自己的机器 ID 列表里面查找是否存在与 uboot 传递进来的 machid 匹配的项目,如果存在就说明 Linux 内核支持这个机器,那么 Linux 就会启动!如果使用设备树的话这个 machid 就无效了,设备树存有一个“兼容性”这个属性,Linux 内核会比较“兼容性”属性的值(字符串)来查看是否支持这个机器。

  2. 第 295 行,函数 kernel_entry,看名字“内核_进入”,说明此函数是进入 Linux 内核的,也就是最终的大boss!此函数有三个参数:zero,arch,params,第一个参数 zero 同样为 0;第二个参数为机器 ID;第三个参数 ATAGS 或者设备树(DTB)首地址,ATAGS 是传统的方法,用于传递一些命令行信息啥的,如果使用设备树的话就要传递设备树(DTB)。

  3. 第 299 行,获取 kernel_entry 函数,函数 kernel_entry 并不是 uboot 定义的,而是 Linux 内核定义的,Linux 内核镜像文件的第一行代码就是函数 kernel_entry,而 images->ep 保存着 Linux内核镜像的起始地址,起始地址保存的正是 Linux 内核第一行代码!

  4. 第 313 行,调用函数 announce_and_cleanup 来打印一些信息并做一些清理工作:
    image
    因此每次启动 Linux 之前输出“Starting kernel ...”信息如下:
    image

  5. 继续回到函数 boot_jump_linux,第 315~318 行是设置寄存器 r2 的值?为什么要设置 r2 的值呢?Linux 内核一开始是汇编代码,因此函数 kernel_entry 就是个汇编函数。向汇编函数传递参数要使用 r0、r1 和 r2(参数数量不超过 3 个的时候),所以 r2 寄存器就是函数 kernel_entry 的第三个参数。

  6. 第 316 行,如果使用设备树的话,r2 应该是设备树的起始地址,而设备树地址保存在 images的 ftd_addr 成员变量中。

  7. 第 317 行,如果不使用设备树的话,r2 应该是 uboot 传递给 Linux 的参数起始地址,也就是环境变量 bootargs 的值,

  8. 最后调用调用 kernel_entry 函数进入 Linux 内核,至此Uboot的整个运行流程结束,uboot 的使命也就完成了。

3.总结bootz启动过程

image

标签:BOOTM,uboot,bootz,image,bootm,STATE,Linux,os
From: https://www.cnblogs.com/fuzidage/p/17960265

相关文章

  • uboot-4_U-Boot启动流程
    下面以u-boot2016为例,一行一行分析armv7架构cpu的uboot启动流程,用到的soc是imx6ull为例。总体流程如下:分为2部分:arch级初始化(架构)和板级初始化:1reset函数1.1初始化异常向量表我们知道启动入口是arch/arm/lib/vectors.S文件中的_start:从函数入口_start可以看到,入口的......
  • 全志H3移植uboot
    香橙派全志H3烧录Uboot,远程加载zImage,dtb,rootfs_全志h3可以刷什么-CSDN博客 //烧入uboot到sd中,通过tftp挂载linux内核设备树,通过nfs来挂载根文件系统香橙派全志H3烧入U-boot和Linux内核以及配置_香橙派3刷linux-CSDN博客  //详细讲解sd分区直接把linux内核设备树烧入到s......
  • lk uboot传参到Kernel
    记录一下内核和uboot的传参MTK传参 1.在app/mt_boot/mt_boot.c使用cmdline_append(buf); snprintf(buf,10,"vcom=%s",vcom_str);pal_log_err("%s\n",buf);cmdline_append(buf); 2.在kernel中读取br_ptr=strstr(saved_command_line,"vcom="......
  • ubuntu 18.04.6 编译Preloader提示 没有规则可制作目标 /host_tools/altera/preloader
     生成spl_bsp后,在spl_bsp路径下输入make 提示:没有规则可制作目标/host_tools/altera/preloader/uboot-socfpga.tar.gz 原来要先运行 ./embeddedcommandshell.sh,并在该终端窗口下输入make   ......
  • ubuntu 18.04.6编译uboot提示error: bad value (‘generic-armv7-a’) for ‘-mtune=
    按照按照  (https://rocketboards.org/foswiki/Documentation/EmbeddedLinuxBeginnerSGuide)制作了一个image当编译uboot的时候,发送命令make:makesocfpga_cyclone5_configmake 得到提示:cc1:error:badvalue(‘generic-armv7-a’)for‘-mtune=’switchcc1:note:va......
  • 为什么EmbeddedLinuxBeginnerSGuide的image中 uboot一定要放在fat32分区,不能跟preload
    按照按照  (https://rocketboards.org/foswiki/Documentation/EmbeddedLinuxBeginnerSGuide)制作了一个image,然后按照https://www.cnblogs.com/DoreenLiu/p/17903782.html将相关文件都打包到一个.img文件里面去。其实最开始研发给我的Makefile内容是这样(这个是RD用于制作LXD......
  • Uboot-3链接脚本lds分析
    1u-boot.lds解读(armv8)文件位于u-boot-2021.10\arch\arm\cpu\armv8\u-boot.lds。分析过程已在lds内部注释了./*SPDX-License-Identifier:GPL-2.0+*//**(C)Copyright2013*DavidFeng<fenghua@phytium.com.cn>**(C)Copyright2002*GaryJennejohn,DENXSof......
  • 04_uboot全面讲解
    04_uboot全面讲解本课程希望达到目标理解底层代码的编写方式u-boot版本选择uboot官方源码地址https://ftp.denx.de/pub/u-boot/Uboot版本一直在迭代,加入的东西也越来越多,所以我们学习,只要选择适合的版本就可以了这里我们先选择下载2010.12版本的解压下来之后,进入\arch\a......
  • UBUNTU 18.04.6 的Quartus里面转换sof到rbf文件在uboot阶段加载时出错或者在kernel启
    参考Intel的SD卡image设计的教程(https://rocketboards.org/foswiki/Documentation/EmbeddedLinuxBeginnerSGuide) 确认DE10-Nano的MSEL设置为01010,插上SD卡 给DE10-Nano上电,发现可以启动,但卡死在这里不动了: 如果只测试Preloader和uboot的时候也有这个错误: ......
  • uboot移植及图形化配置
    一、编译通过官方的uboot,修改uboot,参考文档一些配置文件,lcd、网络配置二、图形化配置界面1.指定默认配置文件makemx6ull_alientek_emmc_defconfig2.打开图形化配置界面makemenuconfig3.完成配置后编辑完成之后要保存好当前的配置文件如./configs/test_defconfigsave ......