uboot(二)—— crt0_64.S(board_init_f函数)

目录

一、crt0_64.S

二、board_init_f函数

三、init_sequence_f[] 函数数组(一)

四、init_sequence_f[] 函数数组(二)

五、内存分配如图


一、crt0_64.S

文件位置:u-boot-2022.01/arch/arm/lib/crt0_64.S

_main入口

    bl	board_init_f_alloc_reserve
	mov	sp, x0
	/* set up gd here, outside any C code */
	mov	x18, x0
	bl	board_init_f_init_reserve

	mov	x0, #0
	bl	board_init_f
  • 执行3函数,前2个在u-boot-2022.01\common\init\board_init.c 中

    board_init_f_alloc_reserve
    board_init_f_init_reserve
    board_init_f    在u-boot-2022.01\common\board_f.c

  • board_init_f_alloc_reserve,board_init_f_init_reserve主要实现内存排布:
    uboot区,堆区,栈区,gd(bd)
    board_init_f_alloc_reserve:最终算出gd的内存地址,top指向
    board_init_f_init_reserve:实例化gd,并初始化为0

二、board_init_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();
#endif
}


static inline int initcall_run_list(const init_fnc_t init_sequence[])
{
	const init_fnc_t *init_fnc_ptr;

	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		unsigned long reloc_ofs = 0;
		int ret;

		/*
		 * Sandbox is relocated by the OS, so symbols always appear at
		 * the relocated address.
		 */
		if (IS_ENABLED(CONFIG_SANDBOX) || (gd->flags & GD_FLG_RELOC))
			reloc_ofs = gd->reloc_off;
#ifdef CONFIG_EFI_APP  //debug开关
		reloc_ofs = (unsigned long)image_base;
#endif
		if (reloc_ofs)
			debug("initcall: %p (relocated to %p)\n",
					(char *)*init_fnc_ptr - reloc_ofs,
					(char *)*init_fnc_ptr);
		else
			debug("initcall: %p\n", (char *)*init_fnc_ptr - reloc_ofs);

		ret = (*init_fnc_ptr)();
		if (ret) {
			printf("initcall sequence %p failed at call %p (err=%d)\n",
			       init_sequence,
			       (char *)*init_fnc_ptr - reloc_ofs, ret);
			return -1;
		}
	}
	return 0;
}

static const init_fnc_t init_sequence_f[] = {
	setup_mon_len,
#ifdef CONFIG_OF_CONTROL
	fdtdec_setup,
#endif
#ifdef CONFIG_TRACE_EARLY
	trace_early_init,
#endif
	initf_malloc,
	log_init,
	initf_bootstage,	/* uses its own timer, so does not need DM */
#ifdef CONFIG_BLOBLIST
	bloblist_init,
#endif
	setup_spl_handoff,
#if defined(CONFIG_CONSOLE_RECORD_INIT_F)
	console_record_init,
#endif
#if defined(CONFIG_HAVE_FSP)
	arch_fsp_init,
#endif
	arch_cpu_init,		/* basic arch cpu dependent setup */
	mach_cpu_init,		/* SoC/machine dependent CPU setup */
	initf_dm,
	arch_cpu_init_dm,
#if defined(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.) */
#endif
#if !defined(CONFIG_M68K)
	timer_init,		/* initialize timer */
#endif
#if defined(CONFIG_BOARD_POSTCLK_INIT)
	board_postclk_init,
#endif
	env_init,		/* initialize environment */
	init_baud_rate,		/* initialze baudrate settings */
	serial_init,		/* serial communications setup */
	console_init_f,		/* stage 1 init of console */
	display_options,	/* say that we are here */
	display_text_info,	/* show debugging info if required */
	checkcpu,
#if defined(CONFIG_SYSRESET)
	print_resetinfo,
#endif
#if defined(CONFIG_DISPLAY_CPUINFO)
	print_cpuinfo,		/* display cpu info (and speed) */
#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,
#endif
	INIT_FUNC_WATCHDOG_RESET
#if CONFIG_IS_ENABLED(SYS_I2C_LEGACY)
	init_func_i2c,
#endif
#if defined(CONFIG_VID) && !defined(CONFIG_SPL)
	init_func_vid,
#endif
	announce_dram_init,
	dram_init,		/* configure available RAM banks */
#ifdef CONFIG_POST
	post_init_f,
#endif
	INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST)
	testdram,
#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
#ifdef CONFIG_PRAM
	reserve_pram,
#endif
	reserve_round_4k,
	arch_reserve_mmu,
	reserve_video,
	reserve_trace,
	reserve_uboot,
	reserve_malloc,
	reserve_board,
	reserve_global_data,
	reserve_fdt,
	reserve_bootstage,
	reserve_bloblist,
	reserve_arch,
	reserve_stacks,
	dram_init_banksize,
	show_dram_config,
	INIT_FUNC_WATCHDOG_RESET
	setup_bdinfo,
	display_new_sp,
	INIT_FUNC_WATCHDOG_RESET
	reloc_fdt,
	reloc_bootstage,
	reloc_bloblist,
	setup_reloc,
#if defined(CONFIG_X86) || defined(CONFIG_ARC)
	copy_uboot_to_ram,
	do_elf_reloc_fixups,
#endif
	clear_bss,
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
		!CONFIG_IS_ENABLED(X86_64)
	jump_to_copy,
#endif
	NULL,
};
  • gd->flags = boot_flags;         
    gd->have_console = 0;
    flags:全局数据标志
    have_console:控制台1可用,0不可用
  • typedef int (*init_fnc_t)(void);   一个函数类型
  • init_sequence是一个函数指针数组,数组中存储了很多个函数指针,这些指向指向的函数都是init_fnc_t类型(参数是void类型,返回值是int)
    都是board级别的各种硬件初始化
  • 函数:int initcall_run_list(const init_fnc_t init_sequence[])
    返回值int,参数是一个二级指针init_sequence这个函数指针数组
  • for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
    依次执行init_sequence这个函数指针数组里的函数,直到NULL退出循环
    函数执行出错返回-1,退出到board_init_f()函数,进入hang()函数
  • hang() 死循环,只能重新上电

三、init_sequence_f[] 函数数组(一)

串口、定时器、设备树、malloc、cpu、DM驱动模型、dram、

static const init_fnc_t init_sequence_f[] = {
	setup_mon_len,
	fdtdec_setup,

	initf_malloc,
	log_init,
	initf_bootstage,	/* uses its own timer, so does not need DM */

	setup_spl_handoff,

	arch_cpu_init,		/* basic arch cpu dependent setup */
	mach_cpu_init,		/* SoC/machine dependent CPU setup */
	initf_dm,
	arch_cpu_init_dm,

	get_clocks,		/* get CPU and bus clocks (etc.) */

	board_postclk_init,

	env_init,		/* initialize environment */
	init_baud_rate,		/* initialze baudrate settings */
	serial_init,		/* serial communications setup */
	console_init_f,		/* stage 1 init of console */
	display_options,	/* say that we are here */
	display_text_info,	/* show debugging info if required */
	checkcpu,

	announce_dram_init,
	dram_init,		/* configure available RAM banks */

	testdram,
	
	setup_dest_addr,

	reserve_pram,

	reserve_round_4k,
	arch_reserve_mmu,
	reserve_video,
	reserve_trace,
	reserve_uboot,
	reserve_malloc,
	reserve_board,
	reserve_global_data,
	reserve_fdt,
	reserve_bootstage,
	reserve_bloblist,
	reserve_arch,
	reserve_stacks,
	dram_init_banksize,
	show_dram_config,

	setup_bdinfo,
	display_new_sp,

	reloc_fdt,
	reloc_bootstage,
	reloc_bloblist,
	setup_reloc,

	clear_bss,

	NULL,
};
  • setup_mon_len:设置 gd 的 mon_len 成员变量,整个代码的长度
  • fdtdec_setup:获取设备树地址
  • initf_malloc:设置gd 的malloc_limit,malloc内存池大小
    CONFIG_SYS_MALLOC_F_LEN=0x2000
  • log_init,initf_bootstage,setup_spl_handoff:什么也没做返回0
  • arch_cpu_init:硬件 CPU初始化
  • mach_cpu_init:特定SoC的初始化
  • initf_dm,arch_cpu_init_dm:DM驱动模型的一些初始化,DM驱动模型参考
  • get_clocks:获取一些时钟值
  • timer_init:初始化定时器,为 uboot 提供时间
  • board_postclk_init:对于 I.MX6ULL 来说是设置 VDDSOC 电压
  • env_init:设置 gd 的成员变量 env_addr,也就是环境变量的保存地址
  • init_baud_rate:初始化波特率,env_get函数用来读取环境变量的值 baudrate
    初始化 gd->baudrate
    baudrate初始化时的规则是:先去环境变量中读取"baudrate"这个环境变量的值。如果读取成功则使用这个值作为环境变量,记录在gd->baudrate中;如果读取不成功则使用CONFIG_BAUDRATE的值作为波特率
  • serial_init:初始化串口
    加一句自己调试,验证初始化成功
    drivers/serial/serial-uclass.c 
    U-Boot 2022.09.21xiaowei (Oct 01 2022 - 22:53:14 -0700)
    
    DRAM:  128 MiB
    128 MiB
    RPI 3 Model B (0xa32082)
    xw: serial
    MMC:   mmc@7e202000: 0, sdhci@7e300000: 1
    Loading Environment from FAT... *** Warning - bad CRC, using default environment
    
    In:    serial
    Out:   vidconsole
    Err:   vidconsole
    Net:   No ethernet found.
    starting USB...
    Bus usb@7e980000: USB DWC2
    scanning bus usb@7e980000 for devices... 3 USB Device(s) found
           scanning usb for storage devices... 0 Storage Device(s) found
    Hit any key to stop autoboot:  0 
    U-Boot> 
  • console_init_f:设置 gd->have_console 为 1表示有个控制台,此函数也将前面暂存在缓冲区中的数据通过控制台打印出来。
  • display_options:通过串口输出一些信息,如u-boot的版本信息,注释到可以发现版本信息没有了
    lib/display_options.c 
    MESS:00:00:03.389240:0: uart: Baud rateDRAM:  128 MiB
    128 MiB
    RPI 3 Model B (0xa32082)
    xw: serial init
    xw: pirntf serial init
    xw: env_addr: 133816044
    MMC:   mmc@7e202000: 0, sdhci@7e300000: 1
    Loading Environment from FAT... *** Warning - bad CRC, using default environment
    
    In:    serial
    Out:   vidconsole
    Err:   vidconsole
    Net:   No ethernet found.
    starting USB...
    Bus usb@7e980000: USB DWC2
    scanning bus usb@7e980000 for devices... 3 USB Device(s) found
           scanning usb for storage devices... 0 Storage Device(s) found
    Hit any key to stop autoboot:  0 
    U-Boot> 
  • display_text_info:打印一些文本信息,如果开启 UBOOT 的 DEBUG 功能的话就会输出 text_base、bss_start、bss_end
    开启DEBUG方法:在include/common.h文件添加 #define DEBUG
    也可以自己添加调试信息打印(printf)
    xw: u-boot code: 00080000 -> 00104340  BSS: -> 0010F130
  • checkcpu:什么也没做返回0
  • announce_dram_init:打印字符串DRAM: 
  • dram_init:DRAM初始化
  • testdram:测试DRAM,并打印一些信息

现在我们已经映射了DRAM并开始工作,我们可以重新定位代码并继续从DRAM运行

四、init_sequence_f[] 函数数组(二)

对uboot重定位的一些地址设置

  • setup_dest_addr:uboot重定位设置gd->ram_size,gd->ram_top,gd->relocaddr这三个的值
    xw: gd->ram_size: 0x8000000  //RAM大小128M
    xw: gd->ram_top: 0x7fe0000   //U-Boot使用的RAM顶部地址
    xw: gd->relocaddr: 0x7fe0000 //RAM中U-Boot的起始地址,跟随设置空间变化
  • reserve_round_4k:对gd->relocaddr做4KB对齐
  • arch_reserve_mmu:预留空间存放TLB表,以及64kb对齐
    文件位置:arch\arm\lib\cache.c
    xw: cache:arm_reserve_mmu:
        gd->arch.tlb_size = 00008000 //TLB 表大小32kb
        gd->arch.tlb_addr = 07fd0000    //TLB 表起始地址, 64KB 对齐以后
        gd->relocaddr = 07fd0000        //现在地址,7fe0000-7fd0000=64kb
  • reserve_trace:留出跟踪调试的内存
  • reserve_uboot: 留出重定位后的 uboot 所占用的内存区域
    xw: board_f.c:reserve_uboot:gd->mon_len=0008f3b0  //uboot 所占用大小
    xw: board_f.c:reserve_uboot:gd->relocaddr=07f40000 //4K 字节对齐,现在的地址,大小90000,576kb
    xw: board_f.c:reserve_uboot:gd->start_addr_sp=07f40000 // 栈指针地址
  • reserve_malloc:留出malloc区域
    xw: board_f.c:reserve_malloc:TOTAL_MALLOC_LEN = 00404000 //长度大小,4M
    xw: board_f.c:reserve_malloc:gd->start_addr_sp = 07b3c000M
    malloc 区域由宏TOTAL_MALLOC_LEN 定义
  • reserve_board:预留bd_info结构体大小空间,并清零
    xw: board_f.c:reserve_board:gd->bd(struct bd_info) = 136byte
    xw: board_f.c:reserve_board:gd->start_addr_sp = 07b3bf70    
    //7b3bf70-7b3bf70=144   多预留8b
  • reserve_global_data:预留空间给gd_t结构体
    xw: board_f.c:reserve_global_data:gd_t = 408byte
    xw: board_f.c:reserve_global_data:gd->start_addr_sp = 07b3bdd0
    //07b3bf70-07b3bdd0=416  多预留8b
  • reserve_fdt:预留空间给设备树驱动,没有使用,所以没预留
    xw: board_f.c:reserve_fdt:gd->fdt_size = 0byte
    xw: board_f.c:reserve_fdt:gd->start_addr_sp = 07b3bdd0
  • reserve_bootstage,reserve_bloblist:什么也没做
  • reserve_arch:空函数
  • reserve_stacks:预留空间给栈16字节
    xw: board_f.c:reserve_stacks:gd->start_addr_sp = 07b3bdc0
  • dram_init_banksize:设置 dram 信息,gd->bd->bi_dram[0].start,gd->bd->bi_dram[0].size
  • show_dram_config:显示 DRAM 的配置start,size 
    xw: board_f.c:show_dram_config:gd->bd->bi_dram[0].start = 0
    xw: board_f.c:show_dram_config:gd->bd->bi_dram[0].size = 8000000
  • setup_bdinfo:什么也没做
  • display_new_sp:debug打印当前start_addr_sp
    xw: board_f.c:display_new_sp:gd->start_addr_sp = 07b3bdc0
  • reloc_fdt,reloc_bootstage,reloc_bloblist:什么也没做
  • setup_reloc:设置gd结构体的其他一些成员变量,供后面重定位的时候使用,并且将以前的 gd 拷贝到 gd->new_gd 处
    xw: board_f.c:setup_reloc:gd->reloc_off = 07ec0000
    xw: board_f.c:setup_reloc:gd->relocaddr = 07f40000 //重定位后uboot地址
    xw: board_f.c:setup_reloc:gd->new_gd = 07b3bdd0    //gd首地址
    xw: board_f.c:setup_reloc:gd->start_addr_sp = 07b3bdc0 //sp
  • clear_bss:空函数

五、内存分配如图

 

参考博文1
参考博文2
参考博文3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dz小伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值