bootz启动 Linux内核过程中涉及的 bootz_start 函数

一.  bootz启动Linux

uboot 启动Linux内核使用bootz命令。当然还有其它的启动命令,例如,bootm命令等等。

本文只分析 bootz命令启动 Linux内核的过程中涉及的几个重要函数。具体分析 bootz_start 函数执行过程。

本文继上一篇文章,地址如下:

bootz启动 Linux内核过程中涉及的 do_bootz 函数_凌肖战的博客-优快云博客

二.  bootz 启动 Linux 内核涉及函数

上一篇文章简单分析,可以知道:

bootz 命令的执行函数为 do_bootz函数。而 do_bootz函数主要调用如下函数:

bootz_start 函数,bootm_disable_interrupts 函数,设置 images.os.os ,do_bootm_states 函数。

1.  bootz_start 函数

bootz_srart 函数也定义在文件 cmd/bootm.c 中,函数内容如下:
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;

	ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,
			      images, 1);

	/* Setup Linux kernel zImage entry point */
	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);
	}

	ret = bootz_setup(images->ep, &zi_start, &zi_end);
	if (ret != 0)
		return 1;

	lmb_reserve(&images->lmb, images->ep, zi_end - zi_start);

	/*
	 * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not
	 * have a header that provide this informaiton.
	 */
	if (bootm_find_images(flag, argc, argv))
		return 1;

#ifdef CONFIG_SECURE_BOOT
	extern 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;
	}
#endif
	return 0;
}

7 行,调用 do_bootm_states 函数,执行 BOOTM_STATE_START 阶段。 这里执行部分的代码如下:
int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
		    int states, bootm_headers_t *images, int boot_progress)
{
	boot_os_fn *boot_fn;
	ulong iflag = 0;
	int ret = 0, need_boot_fn;

	images->state |= states;

	/*
	 * Work through the states and see how far we get. We stop on
	 * any error.
	 */
	if (states & BOOTM_STATE_START)
		ret = bootm_start(cmdtp, flag, argc, argv);
..........

	return ret;
}

处理 BOOTM_STATE_START 阶段, bootz_start 会执行这一段代码,这里调用函数 bootm_start 函数,此函数定义在文件 common/bootm.c 中,函数内容如下:
static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc,
		       char * const argv[])
{
	memset((void *)&images, 0, sizeof(images));
	images.verify = getenv_yesno("verify");

	boot_start_lmb(&images);

	bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start");
	images.state = BOOTM_STATE_START;

	return 0;
}

可以看出,bootm_start 函数对images全局变量清零,设置image的状态等。

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

来看一下 bootz_setup 函数,此函数定义在文件 arch/arm/lib/bootm.c 中,函数内容如下:
#define	LINUX_ARM_ZIMAGE_MAGIC	0x016f2818

int bootz_setup(ulong image, ulong *start, ulong *end)
{
	struct zimage_header *zi;

	zi = (struct zimage_header *)map_sysmem(image, 0);
	if (zi->zi_magic != LINUX_ARM_ZIMAGE_MAGIC) {
		puts("Bad Linux ARM zImage magic!\n");
		return 1;
	}

	*start = zi->zi_start;
	*end = zi->zi_end;

	printf("Kernel image @ %#08lx [ %#08lx - %#08lx ]\n", image, *start,
	      *end);

	return 0;
}

1 行,宏 LINUX_ARM_ZIMAGE_MAGIC 就是 ARM Linux 系统魔术数。
zimage_header 的zi_magic为 zImage 的幻数,魔术数。应该为0x016f2818。前面有9个32位的数据,那么9*4=36,0~35,第36个字节的数据开始就是zimage的幻数。可以通过查看 编译好的 zImage文件,确认第36个字节数据是否为 这个魔术值。
7 行,从传递进来的参数 image( 也就是系统镜像首地址 ) 中获取 zimage 头。 zImage 结构体为 zimage_header
8~11 行,判断 image 是否为 ARM Linux 系统镜像,如果不是的话就直接返回,并且打印出 “ Bad Linux ARM zImage magic! ”。
13-14 行初始化函数 bootz_setup 的参数 start end
16 行,打印启动信息,如果 Linux 系统镜像正常的话。会打印如下Log信息:
Kernel image @ 0x80800000 [ 0x000000 - 0x552f80 ]

接下来看一下 bootm_find_images 函数,此函数定义在文件 common/bootm.c 中,函数内容如下:
int bootm_find_images(int flag, int argc, char * const argv[])
{
	int ret;

	/* find ramdisk */
	ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH,
			       &images.rd_start, &images.rd_end);
	if (ret) {
		puts("Ramdisk image is corrupt or invalid\n");
		return 1;
	}

#if defined(CONFIG_OF_LIBFDT)
	/* find flattened device tree */
	ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images,
			   &images.ft_addr, &images.ft_len);
	if (ret) {
		puts("Could not find a valid device tree\n");
		return 1;
	}
	set_working_fdt_addr((ulong)images.ft_addr);
#endif
......
	return 0;
}

6~11 行是跟查找 ramdisk ,但是我们没有用到 ramdisk ,因此这部分代码不用管。
15~20 行是查找设备树 (dtb) 文件,找到以后就将设备树的起始地址和长度分别写到 images
ft_addr ft_len 成员变量中。
我们使用 bootz 启动 Linux 的时候已经指明了设备树在 DRAM 中的存储地址,因此 images.ft_addr=0X83000000 ,长度根据具体的设备树文件而定,比 如,我现在使用的设备树文件长度为 0X8C81 ,因此 images.ft_len=0X8C81
第 21行,设置设备树的起始地址。
bootz_start 函数就讲解到这里, bootz_start 函数 主要用于初始化 images 的相关成员变量。

<think>好的,用户想了解Linux系统启动过程的详细阶段划分。我之前有回答过类似的问题,需要参考之前的引用资料。首先,根据引用[1],启动分为架构相关的引导通用启动过程。引用[2]提到了BIOSBootloader的作用,而引用[3]则详细说明了嵌入式系统中Bootloader的功能。 我需要把启动过程分成几个主要阶段。根据引用[2],BIOS是第一步,然后是Bootloader,接着是内核解压初始化。引用[1]提到zImageuImage自解压成vmlinux,之后进入正常启动流程。然后内核初始化子系统,挂载根文件系统,最后是用户空间初始化,比如systemd或init进程。 用户可能需要每个阶段的简要说明,包括关键步骤,比如BIOS自检、Bootloader加载内核内核解压、初始化硬件、挂载根文件系统,以及用户空间的启动。同时要注意引用对应的资料,比如BIOS部分引用[2],Bootloader引用[3],内核解压引用[1]。 另外,用户可能对每个阶段的具体任务感兴趣,比如Bootloader如何初始化外设,内核初始化的子系统有哪些,比如进程管理、内存管理等。还有根文件系统的挂载,以及用户空间启动的不同初始化系统。 需要确保结构清晰,分阶段说明,每个阶段包含关键步骤对应的引用。最后生成相关问题,帮助用户深入理解各个阶段,比如Bootloader的作用、内核初始化的步骤、不同初始化系统的比较,以及如何选择根文件系统类型。</think>### Linux系统启动过程阶段划分 Linux系统启动过程可分为六个关键阶段,每个阶段承担特定的硬件初始化或软件加载任务: --- #### 一、BIOS/UEFI初始化(硬件层)[^2] 1. **硬件自检**(POST):检测CPU、内存、存储设备等核心硬件 2. **引导设备选择**:按设定顺序查找可启动设备(HDD/USB/Network) 3. **加载引导扇区**:将MBR/GPT中的前512字节代码加载到0x7C00内存地址 4. **控制权移交**:跳转执行Bootloader第一阶段代码 --- #### 二、Bootloader阶段[^3] ```text +-------------------+ +-------------------+ | 第一阶段(汇编代码) | --> | 第二阶段(C语言实现) | +-------------------+ +-------------------+ | | 初始化CPU/内存 加载内核镜像 设置临时堆栈 传递启动参数 识别存储介质 启用硬件特性 ``` 典型Bootloader(如U-Boot)会执行: 1. 初始化时钟/DDR控制器 2. 加载压缩内核镜像到指定内存地址 3. 设置设备树(DTB)或启动参数(ATAGs) 4. 执行`bootm`或`bootz`命令启动内核 --- #### 三、内核解压与初始化[^1] $$ \text{zImage} \xrightarrow{\text{自解压}} \text{vmlinux} $$ 1. 架构相关初始化: - 设置异常向量表(ARM的vector.S) - 创建初始页表(head.S) - 启用MMU 2. 通用内核初始化: - 解析启动参数(`cmdline`) - 初始化调度器(sched_init()) - 内存管理初始化(mm_init()) - 设备树解析(OF_DT) --- #### 四、子系统初始化 ```c start_kernel() ├─> setup_arch() // 架构相关初始化 ├─> trap_init() // 异常处理初始化 ├─> mm_init() // 内存管理子系统 ├─> sched_init() // 进程调度器 ├─> time_init() // 时钟系统 ├─> console_init() // 控制台驱动 └─> rest_init() // 创建init进程 ``` --- #### 五、根文件系统挂载 1. 通过`root=`参数确定根设备位置 2. 常见挂载方式: - 磁盘分区(`root=/dev/sda1`) - NFS网络挂载(`root=/dev/nfs`) - Initramfs临时文件系统 3. 执行`init=/bin/bash`可进入紧急模式 --- #### 六、用户空间初始化 不同初始化系统对比: | 特性 | Systemd | SysVinit | OpenRC | |----------------|-------------------|----------------|----------------| | 并行启动 | 支持 | 不支持 | 有限支持 | | 依赖管理 | 基于单元依赖 | 顺序执行 | 依赖脚本 | | 常用路径 | /etc/systemd/ | /etc/init.d/ | /etc/init.d/ | | 日志系统 | Journald | 独立日志文件 | 独立日志文件 | --- ### 关键流程图解 ```mermaid graph TD A[BIOS/UEFI] --> B[Bootloader] B --> C[内核解压] C --> D[内核初始化] D --> E[挂载根文件系统] E --> F[用户空间初始化] F --> G[登录界面/服务] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值