bootm调用流程

bootm调用流程

本文作为一个笔记,记录bootm启动的流程,参考版本:uboot 2021.01

在执行bootm之前,image已经从sd卡读到了内存中,这个要看uboot的参数,是从哪里读取读到哪里
下面的是qemu的下载命令:uboot的命令可以放在代码里面可以放在环境变量里面也可以放在文件里面,例如boot.scr。
fatload mmc 0 0xa1000000 uImage.lz4
fatload mmc 0 0xa8300000 uInitrd.lz4
fatload mmc 0 0xa8000000 kernel.dtb

bootm – 执行命令 : bootm 0xa1000000 0xa8300000 0xa8000000
do_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) – cmd/bootm.c
A. argc–; argv++; //去掉了命令参数中的argv[0],也就是bootm

	B.	// 如果states包含BOOTM_STATE_OS_GO此函数最终就会boot an OS, 那么这个函数就不会返回了,除非出错了。
		// 这里传入的States是0x71f,所以会执行很多子函数
		do_bootm_states(cmdtp, flag, argc, argv, states, &images, 1) -- common/bootm.c
			1.1	if (states & BOOTM_STATE_START)
					ret = bootm_start(cmdtp, flag, argc, argv);     -- common/bootm.c
						memset 全局变量images,image状态设置为start
						
			2.1	if (!ret && (states & BOOTM_STATE_FINDOS))
					ret = bootm_find_os(cmdtp, flag, argc, argv);    -- common/bootm.c
							2.1.1	boot_get_kernel  -- 读取image的64 bytes的头
									//获取image的内存地址,是在调用bootm之前,由其他程序把image读到内存中,不同的介质不同的读取方法。
									// 从bootm的参数里面获取这个image的地址,argv在do_bootm里面做了++
									img_addr = genimg_get_kernel_addr_fit(argc < 1 ? NULL : argv[0],&fit_uname_config, &fit_uname_kernel); 
									hdr = image_get_kernel(img_addr, images->verify);   获取image的头信息
										image_print_contents(hdr); -- 打印头信息,类似下面的信息:
											   Image Name:   Linux
											   Image Type:   RISC-V Linux Kernel Image (lz4 compressed)
											   Data Size:    4025467 Bytes = 3.8 MiB
											   Load Address: a0400000
											   Entry Point:  a0400000									
										image_check_dcrc(hdr)  -- crc校验image
									memmove(&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t)); -- 拷贝头信息,避免解压的时间覆盖头信息
							2.1.2	根据上面获取到header信息设置images.os中的变量,类似下面的信息:
				走到这里kernel的所有信息都从header中获取了,如image类型,压缩类型,load地址,entry地址,size等等			
							
			3.1	if (!ret && (states & BOOTM_STATE_FINDOTHER))
					通过bootm的参数,试图获取有效的image,并把信息保存在images里面
					ret = bootm_find_other(cmdtp, flag, argc, argv);    -- common/bootm.c
						 boot_get_ramdisk  -- 获取ramdisk,保存ramdisk的信息,并打印如下:
							## Loading init Ramdisk from Legacy Image at a8300000 ...
							Image Name:   Initrd
						    Image Type:   RISC-V Linux RAMDisk Image (lz4 compressed)
						    Data Size:    5487619 Bytes = 5.2 MiB
						    Load Address: 00000000
						    Entry Point:  00000000
						    Verifying Checksum ... OK
						 boot_get_fdt    --  获取dtb,并打印如下:
							## Flattened Device Tree blob at a8000000
								Booting using the fdt blob at 0xa8000000

			4.1	/* Load the OS */
				if (!ret && (states & BOOTM_STATE_LOADOS)) {
					iflag = bootm_disable_interrupts();
					//主要做的就是从内存中0xa1000040读取kernel,跳过了64bytes的header,
					//并根据压缩类型进行解压缩,并把解压缩的image放在Load Address中即0xa0400000
					ret = bootm_load_os(images, 0);      -- common/bootm.c
						image_decomp() -- riscv qemu使用的是lz4,所以会使用lz4解压缩
							//load_buf=0xa0400000 image_buf=0xa1000040, 直接从0xa1000000读取,跳过uboot header,解压到load到地址
							ulz4fn(image_buf, image_len, load_buf, &size);  
								LZ4_decompress_generic()
					到这里uimage经过了去头,解压缩的动作,后面可以直接跳过去执行了
					
			5.1	if (!ret && (states & BOOTM_STATE_RAMDISK)) {
					//重定位ramdisk的位置- relocate init ramdisk
					ret = boot_ramdisk_high(&images->lmb, images->rd_start,rd_len, &images->initrd_start, &images->initrd_end);
	
			6.1	boot_fn = bootm_os_get_boot_func(images->os.os);
					通过os的类型,获取回调函数,linux的是 do_bootm_linux
					这个函数会根据arch来实现,每一个arch下面都有一个,riscv调用的在bootm.c	arch\riscv\lib
			
			7.1	ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
					//调用riscv的do_bootm_linux,根据falge 来执行准备工作,只是准备工作,不是boot
					//一般就是做boot前的检查
						if (flag & BOOTM_STATE_OS_PREP) {
							boot_prep_linux(images);
							return 0;
						}

			8.1	ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,images, boot_fn);
					//根据参数BOOTM_STATE_OS_GO,进行最后的boot工作,
					boot_fn(state, argc, argv, images);   ---去引导kernel了,不会返回了,除非是Stand-alone program
							boot_jump_linux(images, flag);
								kernel = (void (*)(ulong, void *))images->ep; 也就是最前面获取到entry地址0xa0400000
								kernel(gd->arch.boot_hart, images->ft_addr);   -- 启动kernel,后面就交给了kernel,传入的是machine id和dtb的地址
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值