U-boot 启动流程分析 3

board_init_f函数是U-Boot早期初始化的关键部分,它涉及获取UBOOT长度、初始化内存分配、配置控制台缓冲区、CPU架构初始化、环境变量设置、串口初始化等多个步骤。函数通过遍历执行init_sequence_f数组中的回调函数来完成这些任务,包括对DTB的验证、trace初始化、malloc设置等。最后,该函数会对内存进行预留,并进行重定位操作,为后续运行做好准备。
摘要由CSDN通过智能技术生成

下面详细介绍board_init_f函数的调用流程

board_init_f主要做一些运行环境的初始化,如:
获取uboot 的长度,获取fdt的地址,并进行合法化检查,初始化trace,初始化mem malloc,配置console buffer,cpu 架构的初始化,环境变量的初始化,串口的初始化,打印板子的一些信息,然后对内存进行reserve划分,初始化gd里面的变量,重定位fdt,最后重定位uboot自己,不在返回。

1、board_init_f函数很简单,关键就是遍历执行数组init_sequence_f里面的函数

void board_init_f(ulong boot_flags)
{
	gd->flags = boot_flags;
	gd->have_console = 0;

	if (initcall_run_list(init_sequence_f))
		hang();

#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
		!defined(CONFIG_EFI_APP) && !CONFIG_IS_ENABLED(X86_64) && \
		!defined(CONFIG_ARC)
	/* NOTREACHED - jump_to_copy() does not return */
	hang();      /* 除了上面的core, 其他的应该在initcall_run_list 就不再返回了,否则就是出错了 */
#endif
}

2、init_sequence_f 数组内容,也就是board_init_f调用的回调函数。


static const init_fnc_t init_sequence_f[] = {
	setup_mon_len, //设置 gd 的 mon_len 成员变量,此处为 __bss_end - _start,即整个代码的长度
#ifdef CONFIG_OF_CONTROL
	/*
	 * 对dtb进行合法性验证: 
	 * 1.获取fdt的地址. 
	 * 2.通过fdtdec_prepare_fdt来对fdt进行合法性检查,判断dtb是否存在,以及是否有四个字节对齐。
	 * 3.然后再调用fdt_check_header看看头部是否正常,fdt_check_header主要是检查dtb的magic是否正确
	 */
	fdtdec_setup, 
#endif
#ifdef CONFIG_TRACE_EARLY
	trace_early_init,//用于初始化trace,以便u-boot进行trace debug
#endif
	initf_malloc, //初始化 gd 中跟 malloc 有关的成员变量,比如 malloc_limit,表示 malloc 内存池大小
	//初始化list gd->log_head,把能输出log的device-driver加入到list里面
	log_init,
	initf_bootstage,	/* uses its own timer, so does not need DM, 在gd->bootstage里面找一个地方,记录board_init_f()的启动状态 */
#ifdef CONFIG_BLOBLIST
	bloblist_init,
#endif
	setup_spl_handoff, /* CONFIG_HANDOFF未配置,因此该函数仅返回0 */
	initf_console_record,/*申请gd->console_out和gd->console_in,用于启动控制台的记录buffer*/
#if defined(CONFIG_HAVE_FSP)
	arch_fsp_init,/* only for intel platform */
#endif
	/*
	 * 用于基于特定架构下的cpu初始化操作。该函数是一个弱函数,如果特定架构下的代码没有重新实现这个函数功能,那么这个函数将什么也不做
	 * risc-v 架构没看到实现
	 */
	arch_cpu_init,		/* basic arch cpu dependent setup */
	/*
	 * 与arch_cpu_init函数类似,该函数是一个弱函数,SoC/平台相关的CPU设置
	 */
	mach_cpu_init,		/* SoC/machine dependent CPU setup */
	/*
	 * dm:驱动模型,类似于kernel的driver的通用框架,使用probe进行初始化驱动
	 * 使用 initf_dm创建一个dm_root并将其绑定到"root driver”(driver),
	 * 然device_probe 来激活这个设备。第二步使用dm_scan来绑定设备树中的设备和驱动到dm_root下面。
	 */
	initf_dm, 
	/* 做cpu的一些初始化 */
	arch_cpu_init_dm,
#if defined(CONFIG_BOARD_EARLY_INIT_F)
// 这个函数由移植者提供,通常定义在开发板目录下,做一些板级的初始化。
// 提供这个函数的同时还需要定义配置宏CONFIG_BOARD_EARLY_INIT_F,这样才能将该函数真正编译进去
	board_early_init_f,
#endif

#if defined(CONFIG_PPC) || defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)
	/* get CPU and bus clocks according to the environment variable */
	get_clocks,		/* get CPU and bus clocks (etc.),获取时钟参信息,并填到gd里面 */
#endif

#if !defined(CONFIG_M68K)
	//与具体体系结构和处理器芯片相关,初始化定时器,通过这个定时器来为u-boot提供时间参数
	timer_init,		/* initialize timer */
#endif

#if defined(CONFIG_BOARD_POSTCLK_INIT)
	board_postclk_init,
#endif

	/*
	 * 该函数用于存储环境变量的环境初始化。
	 * 该函数的实现本质是:设置gd的成员变量env_addr,也就是环境变量的保存地址。
	 */
	env_init,		/* initialize environment */

	//初始化波特率,根据CONFIG_BAUDRATE来初始化gd->baudrate
	init_baud_rate,		/* initialze baudrate settings */

	//初始化串口,通过default_serial_console获取当前的串口驱动,
	//根据自己的板子上的串口类型,实现串口驱动.
	serial_init,		/* serial communications setup */

	//控制台初始化
	console_init_f,		/* stage 1 init of console */

	//输出一些关于u-boot的一些信息,如版本,编译时间等等
	display_options,	/* say that we are here */

	//输出text,bss段的信息
	display_text_info,	/* show debugging info if required */

	//打印出cpu相关的信息,根据不同架构或者芯片来实现该函数
	checkcpu,
#if defined(CONFIG_SYSRESET)
	print_resetinfo,
#endif
#if defined(CONFIG_DISPLAY_CPUINFO)
	print_cpuinfo,		/* display cpu info (and speed),根据框架实现,基本上都是打印cpu的一些信息*/
#endif
#if defined(CONFIG_DTB_RESELECT)
	embedded_dtb_select,
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
	show_board_info, //打印板子的信息
#endif
	INIT_FUNC_WATCHDOG_INIT //看门狗的初始化
#if defined(CONFIG_MISC_INIT_F)
	misc_init_f,  //misc设备的初始化
#endif
	INIT_FUNC_WATCHDOG_RESET   //看门狗reset,避免watchdog触发板子的启动
#if defined(CONFIG_SYS_I2C)
	init_func_i2c, //初始化iic
#endif
#if defined(CONFIG_VID) && !defined(CONFIG_SPL)
	init_func_vid,
#endif
	announce_dram_init, //only 打印 DRAM:  
	dram_init,		/* configure available RAM banks,不是初始化DRAM,只是设置gd->sram_sized的值,并打印dram的信息 */
#ifdef CONFIG_POST
	post_init_f,
#endif
	INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST)
	testdram, //测试dram,板级代码
#endif /* CONFIG_SYS_DRAM_TEST */
	INIT_FUNC_WATCHDOG_RESET

#ifdef CONFIG_POST
	init_post,
#endif
	INIT_FUNC_WATCHDOG_RESET
	/*
	 * Now that we have DRAM mapped and working, we can
	 * relocate the code and continue running from DRAM.
	 *
	 * Reserve memory at end of RAM for (top down in that order):
	 *  - area that won't get touched by U-Boot and Linux (optional)
	 *  - kernel log buffer
	 *  - protected RAM
	 *  - LCD framebuffer
	 *  - monitor code
	 *  - board info struct
	 */
	setup_dest_addr, //打印各种地址信息
#ifdef CONFIG_OF_BOARD_FIXUP
	fix_fdt,
#endif

	//	下面reserve_开头的函数都是预留一些地址,填充gd里面的信息,方便后续使用
#ifdef CONFIG_PRAM
	reserve_pram,
#endif
	reserve_round_4k,
	arch_reserve_mmu,
	reserve_video,
	reserve_trace,
	reserve_uboot,
	reserve_malloc,
	reserve_board,
	setup_machine,
	reserve_global_data,
	reserve_fdt,
	reserve_bootstage,
	reserve_bloblist,
	reserve_arch,
	reserve_stacks,
	dram_init_banksize,
	show_dram_config,  // 打印出dram的配置信息
	INIT_FUNC_WATCHDOG_RESET
	setup_bdinfo,//设置board相关的信息,即设置gd中的bd结构下的变量
	display_new_sp, //打印新的堆栈信息
	INIT_FUNC_WATCHDOG_RESET

	//重定位下面的地址
	reloc_fdt,
	reloc_bootstage,//用于重定位已经存在的启动阶段中的记录
	reloc_bloblist, //重定位bloblist
	setup_reloc,//启动重定位标志来进行启动重定位, 重定位gd地址
#if defined(CONFIG_X86) || defined(CONFIG_ARC)
	copy_uboot_to_ram,
	do_elf_reloc_fixups,
#endif
	clear_bss,//清bss段
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
		!CONFIG_IS_ENABLED(X86_64)
	jump_to_copy, //riscv会走到这里,会在这里进行重定位,arm的会在后门进行重定位,都少不了的
				//	 最终会调用relocate_code,位于start.S,进行重定位,不会返回了,接着往下走
#endif
	NULL,
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值