Linux系统移植⑤:uboot启动流程详解-board_init_f执行过程
_main 中会调用 board_init_f 函数。
board_init_f 函数主要有两个工作:
①初始化一系列外设,比如串口、定时器,或者打印一些消息等。
②初始化 gd 的各个成员变量, uboot 会将自己重定位到 DRAM 最后面的地址区域,也就是将自己拷贝到 DRAM 最后面的内存区域中。
board_init_f源码如下:
其中重点为initcall_run_list函数,其运行初始化序列 init_sequence_f 里面的一些列函数, init_sequence_f 里面包含了一系列的初始化函数, init_sequence_f 也是定义在文件common/board_f.c 中,其中存在大量条件编译函数,用于判断是否执行。
init_sequence_f列表中包含了大量初始化函数,以下给出部分主要函数介绍
在setup_mon_len函数中计算了mon_len的长度,由于设备是ARM因此其计算规则如图:
gd->mon_len的值实际上是U-Boot镜像在内存中的实际占用大小也就是zImage的大小
initf_malloc 函数初始化 gd 中跟 malloc 有关的成员变量,比如 malloc_limit,此函数会设置 gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN=0X400。 malloc_limit 表示 malloc内存池大小。
(剩下部分函数仅做介绍不再查看其源码)
get_clocks 函数:用于获取一些时钟值, I.MX6ULL 获取的是 sdhc_clk 时钟,也就是 SD 卡外设的时钟。
env_init 函数:是和环境变量有关的,设置 gd 的成员变量 env_addr,也就是环境变量的保存地址。
init_baud_rate函数:用于初始化波特率,根据环境变量 baudrate 来初始化 gd->baudrate。
serial_init函数:初始化串口。
console_init_f函数:设置 gd->have_console 为 1,表示有个控制台,此函数也将前面暂存在缓冲区中的数据通过控制台打印出来。
display_options函数:通过串口输出一些信息。
display_text_info函数:打印一些文本信息,如果开启 UBOOT 的 DEBUG 功能的话就会输出 text_base、 bss_start、 bss_end。
print_cpuinfo 函数:用于打印 CPU 信息。
show_board_info 函数:用于打印板子信息,会调用 checkboard 函数。
init_func_i2c 函数:用于初始化 I2C。
post_init_f函数:此函数用来完成一些测试,初始化 gd->post_init_f_time。
reserve_uboot函数: 留出重定位后的 uboot 所占用的内存区域, uboot 所占用大小由gd->mon_len 所指定,留出 uboot 的空间以后还要对 gd->relocaddr 做 4K 字节对齐,并且重新设置 gd->start_addr_sp
reserve_malloc函数:留出 malloc 区域,调整 gd->start_addr_sp 位置, malloc 区域由宏TOTAL_MALLOC_LEN 定义
reserve_board 函数:留出板子 bd 所占的内存区, bd 是结构体 bd_t, bd_t 大小为80 字节。
reserve_global_data 函数:保留出 gd_t 的内存区域, gd_t 结构体大小为 248B。
reserve_fdt函数:留出设备树相关的内存区域。
reserve_stacks函数:留出栈空间,先对 gd->start_addr_sp 减去 16,然后做 16 字节对齐。如果使能 IRQ 的话还要留出 IRQ 相应的内存,具体工作是由 arch/arm/lib/stack.c 文件中的函数 arch_reserve_stacks 完成。
setup_dram_config 函数:设置 dram 信息,就是设置 gd->bd->bi_dram[0].start 和gd->bd->bi_dram[0].size,后面会传递给 linux 内核,告诉 linux DRAM 的起始地址和大小。
display_new_sp 函数:显示新的 sp 位置,也就是 gd->start_addr_sp,不过要定义宏 DEBUG。
setup_reloc函数:设置 gd 的其他一些成员变量,供后面重定位的时候使用,并且将以前的 gd 拷贝到 gd->new_gd 处。需要使能 DEBUG 才能看到相应的信息输出。
至此, board_init_f 函数就执行完成了。
其最终的内存分配图如下: