文章目录
概述
以RK3568平台为例,讲述uboot开发所必须的知识要点。
配置文件
做裁剪或增加某配置项,需要涉及如下文件:
1、configs/xxx_defconfig : 可以在make menuconfig中查看到的配置
2、include/configs/xxx.h :如何确定这个文件名?
该文件名通过: include/config.h(自动生成)确定
启动流程
从u-boot.lds可以查看到uboot.bin的入口函数:
1 OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
2 OUTPUT_ARCH(aarch64)
3 ENTRY(_start)
4 SECTIONS
5 {
6 . = 0x00000000;
7 . = ALIGN(8);
8 .text :
9 {
10 *(.__image_copy_start)
11 arch/arm/cpu/armv8/start.o (.text*)
12 *(.text*)
13 }
arch/arm/cpu/armv8/start.S
cpu是cortex-a55,使用的是armv8内核
代码流程
先进入board_init_f,再进入board_init_r
123 bl board_init_f
188 b board_init_r /* PC relative jump */
common/board_f.c::board_init_f
board_init_f
init_sequence_f : 顺序执行列表中的接口函数
common/board_r.c::board_init_r
board_init_r
init_sequence_r : 顺序执行列表中的接口函数
board_init
board_late_init
run_main_loop
arch/arm/mach-rockchip/board.c::board_init
平台初始化最核心部分
board_init
board_debug_init:串口iomux、clk配置,监听串口输入(获取ctrl+m、ctrl+c等)
init_kernel_dtb:切到kernel dtb
clks_probe : 初始化系统频率
regulators_enable_boot_on:初始化系统电源
set_armclk_rate: __weak, ARM提频(平台有需求才实现)
dvfs_init: 宽温芯片的调频调压
rk_board_init : rk平台具体实现
arch/arm/mach-rockchip/board.c::board_late_init
board_lata_init
rockchip_set_ethaddr : 设置mac地址
rockchip_set_serialno : 设置serialno
setup_boot_mode : 解析reboot xxx命令;识别按键和loader烧写模式、recovery
charge_display : 充电显示
rockchip_show_logo: 显示开机logo
soc_clk_dump : 打印clk tree
rk_board_late_init : __weak, 由各个具体平台进行实现
common/board_r.c::run_main_loop
run_main_loop
common/main.c::main_loop
ENV框架
env/存储类型.c中定义struct env_driver
例:
U_BOOT_ENV_LOCATION(nowhere) = {
.location = ENVL_NOWHERE,
.init = env_nowhere_init,
ENV_NAME("nowhere")
};
#define U_BOOT_ENV_LOCATION(__name) \
ll_entry_declare(struct env_driver, __name, env_driver)
#define ll_entry_declare(_type, _name, _list) \
_type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
__attribute__((unused, \
section(".u_boot_list_2_"#_list"_2_"#_name)))
即:将nowhere(env in mem)env_driver加入位于段u_boot_list_2_xx的列表中
获取对应存储器的env_driver:
common/board_f.c
init_sequence_f
env_init
env_driver_lookup_default
env_driver_lookup // 获取ENVL_NOWHERE对应的env_driver
drv->init // 得到env存放的地址,保存在gd->env_addr
使用env_driver,例如printenv流程
common/board_r.c
init_sequence_r
initr_env_nowhere //这里是rk平台需要在uboot中使用kernel的设备树,需要访问env中的devtype等信息,故加此代码
set_default_env(NULL);
himport_r(&env_htab, (char *)default_environment,
sizeof(default_environment), '\0', flags, 0,0, NULL)
最终,将default_environment放入env_htab(struct hsearch_data)中,这里是env_in_nowhere的流程
其他流程例如nand为:
common/board_r.c
init_sequence_r
initr_env
env_relocate
env_load -> env_nand_load
env_import(buf, 1); //buf: 指定地址下的env数据
himport_r
himport_r同env_in_nowhere流程。
至此,env数据被放到入env_htab表中。那么如何使用呢?
以printenv为例:
cmd/nvedit.c
env_print
hexport_r
hexport_r将遍历上述的env_htab表获取对应数据。
整体流程框图如下:
env_in_nowhere | | |
env_in_nand | => list <=| env core env_htab <=> printenv
env_in_mmc | | | |
V ▲
env_driver.init -- |
env_driver.load -- |
TODO。。。
抽空添加:dtb、DM、platform、gpio-uclass、pinctrl-uclass、clk-uclass、GICv2/v3