u-boot程序框架
_start:(u-boot\arch\arm\cpu\armv8\start.S)
b reset
b save_boot_params //保存重要的寄存器数据
.globl save_boot_params_ret
bl lowlevel_init //底层初始化:关看门狗,设置SRAM。。。
bl _main
_main:(u-boot\arch\arm\lib\crt0.S)
bl board_init_f_alloc_reserve
bl board_init_f_init_reserve //建立C语言运行环境的内存分布
bl board_init_f
bl spl_relocate_stack_gd //重新分配内存
ldr lr, =board_init_r
board_init_f(common\board_f.c)
init_sequence_f
setup_mon_len //设gd->mon_len为__bss_end-_start
initf_malloc, //设gd->malloc_limit为(1KB),gd->malloc_ptr = 0
log_init,
initf_bootstage,
initf_console_record,
arch_cpu_init, //读PRO_ID寄存器内容解析出CPU id到全局变量s5p_cpu_id
mach_cpu_init,
initf_dm, //初始化dm资源,绑定dm驱动到gd中,扫描设备树中dm设备内容
arch_cpu_init_dm,
timer_init, //初始化定时器4和gd->arch中的定时器成员
env_init, //初始化environment
init_baud_rate, //初始化波特率设置
serial_init, //串口设置
console_init_f, //gd->have_console = 1,用CONFIG_SILENT_CONSOLE可让控制台“沉默”
display_options, //打印u-boot版本信息
display_text_info, //开debug时,打印u-boot code的内存地址
announce_dram_init,
dram_init, //初始化gd->ram_size为通过写读SDRAM校验后得到的实际大小
setup_dest_addr, //gd->ram_top,gd->relocaddr设为SDRAM末尾
reserve_round_4k, //gd->relocaddr调整为4KB对齐
reserve_video, //依赖CONFIG_LCD(未定义),为显存预留内存,初始化gd->fb_base
reserve_trace, //依赖CONFIG_TRACE(未定义),初始化gd->trace_buff
reserve_uboot, //预留gd->mon_len个字节给u-boot code,地址存于gd->relocaddr
reserve_malloc, //预留malloc和env区
reserve_board, //预留struct bd_info的空间并清零,地址存于gd->bd
setup_machine, //依赖CONFIG_MACH_TYPE(未定义),设置gd->bd->bi_arch_number
reserve_global_data, //预留struct global_data的空间,地址存于gd->new_gd
reserve_fdt, //预留存放设备树的内存,设置gd->fdt_size和gd->new_fdt
reserve_bootstage, //依赖CONFIG_BOOTSTAGE(未定义),预留存放struct bootstage_data的内存,设置 gd->new_bootstage
reserve_arch,
reserve_stacks, //设置gd->irq_sp(需16B对齐),预留为4个word的地址记到gd->start_addr_sp
dram_init_banksize, //初始化gd->bd->bi_dram
show_dram_config, //打印DRAM的大小
display_new_sp, //打印gd->start_addr_sp的值
reloc_fdt, //将gd->fdt_blob地址的设备树重定位到gd->new_fdt地址上,更新gd->fdt_blob
reloc_bootstage, //依赖CONFIG_BOOTSTAGE(未定义),重定位gd->bootstage内容到gd->new_bootstage,更新 gd->bootstage
setup_reloc, //初始化gd->reloc_off为重定位目标地址与链接地址之差,重定位gd_t内容到gd->new_gd
board_init_r:(common\board_r.c)
init_sequence_r
initr_trace, //依赖CONFIG_TRACE(未定义),trace system函数未实现
initr_reloc, //gd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT;标志重定位完成
initr_reloc_global_data, //重定位全局变量:monitor_flash_len,gd->fdt_blob(CONFIG_OF_EMBED)
initr_barrier,
initr_malloc, //初始化malloc功能和清零malloc区
log_init, //依赖CONFIG_LOG(未定义),初始化log驱动
initr_bootstage, //设进度为BOOTSTAGE_ID_START_UBOOT_R,并记到bootstage(依赖CONFIG_BOOTSTAGE-未定义), show_boot_progress()(未实现)提示进度,枚举bootstage_id罗列了进度id
initr_console_record, //依赖CONFIG_CONSOLE_RECORD(未定义),给console record功能分配内存
bootstage_relocate, //依赖CONFIG_BOOTSTAGE(未定义),重定位gd->bootstage的内容
stdio_init_tables, //初始化标准输入输出设备链表
initr_serial, //调用drivers/serial/serial-uclass.c(依赖CONFIG_DM_SERIAL),在设备树alias节点获得 属性"stdout-path"或"console",从而得到作为标准输入输出的设备节点,生成 UCLASS_SERIAL类的udevice来匹配兼容的驱动及probe;该串行设备记录到 gd->cur_serial_dev;标志GD_FLG_SERIAL_READY
initr_announce, //打印u-boot重定位后起始地址(需开DEBUG)
power_init_board,
initr_env, //通用env层(env/env.c)调用env硬件驱动层(若定义CONFIG_ENV_IS_IN_NAND则在env/nand.c), 加载nand中CONFIG_ENV_OFFSET开始的env数据到栈中,检查crc成功则将其(失败则使用 default_environment复制到堆中,内存地址记录进env_htab,标志置位GD_FLG_ENV_READY 或GD_FLG_ENV_DEFAULT;插入或设置环境变量fdtcontroladdr为gd->fdt_blob
initr_secondary_cpu,
stdio_add_devices, //调用drv_xxx_init()(需开CONFIG_XXX),如drv_lcd_init()(需定义CONFIG_LCD), drv_system_init()则关于串口;驱动通用层填充stdio_dev并注册添加到标准输入输出链表上, 在硬件驱动层做硬件初始化
initr_jumptable, //为函数跳转表(struct jt_funcs定义)分配内存并记录内存地址到gd->jt
console_init_r, //定义CONFIG_SILENT_CONSOLE和环境变量"silent"可标志GD_FLG_SILENT,在标准输入输出设备 表(stdio_add_devices()生成,common/console.c)将首个标志为DEV_FLAGS_INPUT或 DEV_FLAGS_OUTPUT作为控制台io设备,设置环境变量”stdxxx”为设备名,标志GD_FLG_DEVINIT
run_main_loop, //初始化hush解析器(CONFIG_HUSH_PARSER),用环境变量"bootdelay"或设备树节点config的属 性bootdelay作为启动延迟时间,通过hush解析控制台输入的内容打断倒计时并进入命令行; 倒计时期间控制台无输入则执行环境变量或设备树/config节点的bootcmd,最后执行命令bootm 0x30007FC0
main_loop();
main_loop() (common\main.c)
run_preboot_environment_command();
run_command_list(p, -1, 0);
autoboot_command(s);
run_command_list(s, -1, 0);
board_run_command(buff);
do_bootm(NULL, 0, 2, bootm_argv);
do_bootm(NULL, 0, 2, bootm_argv)(common\bootm.c)
do_bootm_states(...)
bootm_start() //环境变量verify决定后续是否对kernel镜像进行校验和检查,lmb(logical memory blocks) 相关内容的初始化
bootm_find_os()
boot_get_kernel() //获取kernel镜像格式为IMAGE_FORMAT_LEGACY,验证镜像hcrc,打印镜像的名字、类型、数据 大小、加载地址和入口地址,验证dcrc(依赖env的verify),判断arch是否支持解析镜像的结 果填充images.os的成员,kernel入口地址记到images.ep,镜像头部地址记到 mages.os.start
bootm_find_other()
boot_get_ramdisk() //解析ramdisk镜像,bootm第三个参数为其地址(如bootm xxx yyy,yyy为对应地址)
boot_get_fdt() //获取和解析设备树镜像内容,设备树镜像的起始地址需在bootm命令第四个参数指明,如bootm xxx yyy zzz,zzz为对应地址
bootm_load_os() //解压os数据或移动到images->os.load地址,所以kernel应有Load Address=Entry Point
boot_ramdisk_high() //重新定位并初始化ramdisk,需定义CONFIG_SYS_BOOT_RAMDISK_HIGH
bootm_os_get_boot_func() //根据os类型获得启动函数boot_fn = do_bootm_linux
boot_selected_os() //通过函数指针boot_fn调用do_bootm_linux(BOOTM_STATE_OS_GO, ...),进而调用 boot_jump_linux(images, BOOTM_STATE_OS_GO)
do_bootm_linux()
boot_jump_linux()
announce_and_cleanup(fake) //打印提示开始启动内核,注销驱动模型下设备驱动;调用 cleanup_before_linux():关L1/2 D-cache和MMU,冲刷掉dcache内数据; 关I-cache,失效I-cache内条目,失效整个分支预测器阵列;执行数据和指 令内存屏障,确保前面的操作完成
kernel_entry(0, machid, r2); //参数r2传递启动参数(tag或设备树)的内存地址,正式跳转到kernel