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

一.  bootz启动Linux

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

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

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

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

二.  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 的相关成员变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值