上一章节中,我们讲到了
cpp
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)
/* NOTREACHED - jump_to_copy() does not return */
hang();
#endif
}
这里的initcall_run_list会调用init_sequence_f这个函数指针里的函数。那么我们接下来分析这个init_sequence_f里的函数。定义太长,我就不列举了。init_sequence_f定义就在u-boot/common/board_f.c。
init_sequence_f内部的函数作用分析
setup_mon_len
这个就在boot/common/board_f.c。
执行:
cpp
gd->mon_len = (ulong)&__bss_end - (ulong)_start;
这里得到uboot image的大小。这个bss_end和start的值都在u-boot/u-boot.lds里定义了。在第一章中也分析了具体的值。
fdtdec_setup
这个定义在u-boot/lib/fdtdec.c
主要执行的就是
cpp
int fdtdec_setup(void)
{
gd->fdt_blob = (ulong *)&__bss_end; // 就这一行
return 0;
}
这里主要做的就是把 gd->fdt_blob 指向设备树二进制数据,告诉系统"设备树在这里"。
initf_malloc
定义在u-boot/common/dlmalloc.c
cpp
int initf_malloc(void)
{
#if CONFIG_VAL(SYS_MALLOC_F_LEN) // 如果开了 early malloc
assert(gd->malloc_base); // 确认 board_init_f_init_reserve 已经设好了
gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN); // 池子大小 = 0x100000 (1MB)
gd->malloc_ptr = 0; // 已用字节 = 0(池子还是空的)
#endif
return 0;
}
这个就是之前board_init_f_alloc_reserve在这里我们空出了1MB的大小。
cpp
ulong board_init_f_alloc_reserve(ulong top) // top = 0x03f00000
{
top -= CONFIG_VAL(SYS_MALLOC_F_LEN); // top = 0x03e00000 ← 抠出 1MB
top = rounddown(top - sizeof(gd), 16);
return top; // 返回 ≈ 0x03dfff00
}
这里就是存储的他的大小和使用情况。
log_init
定义在u-boot/common/log.c
cpp
int log_init(void)
{
struct log_driver *drv = ll_entry_start(struct log_driver, log_driver);
const int count = ll_entry_count(struct log_driver, log_driver);
struct log_driver *end = drv + count;
INIT_LIST_HEAD((struct list_head *)&gd->log_head); // ① 初始化日志链表头
while (drv < end) { // ② 遍历所有日志驱动
struct log_device *ldev;
ldev = calloc(1, sizeof(*ldev)); // ③ 分配一个设备节点
ldev->drv = drv; // ④ 绑定驱动
list_add_tail(&ldev->sibling_node, // ⑤ 挂到链表上
(struct list_head *)&gd->log_head);
drv++;
}
gd->flags |= GD_FLG_LOG_READY; // ⑥ 标记:日志可用
gd->default_log_level = LOGL_INFO; // ⑦ 默认日志级别 = INFO
return 0;
}
U-Boot 的日志系统支持多个日志驱动(输出目标),比如
| 驱动 | 输出到 |
|---|---|
| console | 串口控制台 |
| syslog | 网络 syslog 服务器 |
| ... | ... |
每个驱动用宏注册后,链接器把它们全部排在一起 ,形成一张连续的表ll_entry_start / ll_entry_count 就是读取这张表的起止位置和条目数------不需要手动注册,编译时自动聚合。
initf_bootstage
这个就定义在u-boot/common/board_f.c这里
这里主要是清空数组,之后开始记录每一步的时间。可以说从这里开始,就有了一个秒表,记录每一步的时间。
initf_console_record
这里主要是记录,可能之前已经有了printf了,但是这时候串口还没有初始化,所以将消息先存储。后续再用。
后边太多了,省略点把~,直接调重要的了。
timer_init
初始化定时器,但是在rk3506里是空函数,真正的初始化在**initf_dm**里。
init_baud_rate
就在u-boot/common/board_f.c
cpp
static int init_baud_rate(void)
{
if (gd && gd->serial.baudrate) // 如果之前已经设过了
gd->baudrate = gd->serial.baudrate; // 直接用那个值
else // 否则
gd->baudrate = env_get_ulong("baudrate", 10, // 从环境变量读
CONFIG_BAUDRATE); // 读不到就用默认值
return 0;
}
=========先更到这=======================