笔者把Uboot启动流程分为了七个阶段:
第一阶段:CPU的关键初始化(中断、权限、MMU等)
第二阶段:初始化关键外设+打印信息+设置global_data信息
第三阶段:内存分配(用于uboot重定位)
第四阶段:重定位
第五阶段:继续初始化其他外设
第六阶段:开始主循环
第七阶段:bootz启动流程
6.2 第二阶段:初始化关键外设+打印信息+设置global_data信息
board_init_f函数的流程如下:
board_init_f函数的两个主要工作
- 初始化一系列外设,比如串口、定时器或者打印一写信息等
- 初始化gd的各个成员变量,最终形成一个完整的内存“分配图”,在后面重定位uboot的时候就会用到这个内存“分配图”
1、设置gd->flags = boot_flags;、gd->have_console = 0;
2、调用common/board_f.c中的initcall_run_list函数 来运行common/board_f.c中的初始化序列 init_sequence_f中的一系列初始化函数。
setup_mon_len函数设置gd的mon_len成员变量,此处为__bss_end - _start,也就是整个代码的长度,也就是u-boot镜像的大小(方便后面迁移)initf_malloc函数初始化gd中跟malloc有关的成员变量arch_cpu_init函数初始架构相关的内容initf_dm函数,驱动模型的一些初始化board_early_init_f函数,板子相关的早期的一些初始化设置,I.MX6ULL用来初始化串口的IO配置timer_init,初始化定时器env_init函数是和环境变量有关的,设置gd的成员变量env_addr,也就是环境变量的保存地址init_baud_rate函数用于初始化波特率,根据环境变量baudrate来初始化gd->baudrateserial_init,初始化串口console_init_f,设置gd->have_console为1,表示有个控制台,此函数也将前面暂存在缓冲区中的数据通过控制台打印出来display_options、display_text_info、print_cpuinfo、show_board_info都是打印一些信息init_func_i2c函数用于初始化I2Cdram_init,由于I.MX6ULL是在bootrom的时候就初始化好DDR的,所以此处没啥太大意义- …
6.3 第三阶段:内存分配(用于uboot重定位)
还是common/board_f.c中的初始化序列 init_sequence_f中的一系列初始化函数
-
setup_dest_addr,设置gd->ram_size,gd->ram_top,gd->relocaddr这三个的值。接下来我们会遇到很多跟数值有关的设置,此时relocaddr == ram_top -
reserve_round_4k函数用于对gd->relocaddr做4KB对齐,但是原来就已经对齐了,相当于没用 -
reserve_mmu,留出MMU的TLB表的位置,分配MMU的TLB表内存以后会对gd->relocaddr做64K字节对齐。 -
reserve_uboot, 留出重定位后的uboot所占用的内存区域,uboot所占用大小由gd中的mon_len所指定,留出uboot的空间以后还要对gd->relocaddr做4K字节对齐,并引入gd->start_addr_sp(后续还会更改这个值) -
reserve_malloc,留出malloc区域,调整gd->start_addr_sp位置 -
reserve_board函数,留出板子bd所占的内存区,bd是结构体bd_t,bd_t大小为80字节 -
reserve_global_data函数,保留出gd_t的内存区域,gd_t结构体大小为248B -
reserve_stacks,留出栈空间,先对gd->start_addr_sp减去16,然后做16字节对齐。这里的gd->start_addr_sp就是最终sp寄存器想要的地址 -
setup_reloc,设置gd的其他一些成员变量,计算好u-boot的偏移值,供后面重定位的时候使用,并且将以前的gd拷贝到gd->new_gd处。就是将r9寄存器所指的结构体保存到ddr的新gd内存中 -
…
6.4 第四阶段:重定位
6.4.1 代码重定位
relocate_code函数的流程如下:
relocate_code函数用于代码拷贝,位于arch/arm/lib/relocate.S
1、设置 r1 保存源内存区域的起始地址、r2 保存源内存区域的结束地址、r4 保存偏移量。uboot 拷贝的目标首地址保存在r0寄存器中。
2、在步骤1设置寄存器的过程中,会比较 r0(目的地址) 和 r1(源地址) 是否相等。如果相等,表示不需要拷贝,会执行 relocate_done 函数。
3、调用函数 copy_loop 完成代码拷贝。将U-Boot的整个镜像从r1(源)拷贝到r0(目标)
4、修正重定位表.rel.dyn
.rel.dyn段是存放.text段中需要重定位处理地址的集合,获取偏移后的地址,然后获得该地址中原label的地址,然后加上新的偏移,再存回去即可完成重定位
6.4.2 中断向量表重定位
relocate_vector函数的流程如下
relocate_vector函数用于重定位向量表
1、设置VBAR寄存器为新的中断向量表的首地址。这个地址就是重定位后 uboot 的首地址,向量表就是从uboot 的首地址开始存放的
6.5 第五阶段:继续初始化其他外设
board_init_r函数的流程如下
board_init_r函数用于继续初始化其他外设
1、调用initcall_run_list函数 来运行common/board_r.c中的初始化序列 init_sequence_r中的一系列初始化函数。
initr_reloc函数用于设置gd->flags,标记重定位完成。initr_caches函数用于初始化cache,使能cache。initr_malloc函数,初始化malloc。initr_serial函数,初始化串口。initr_mmc函数,初始化EMMC,如果使用EMMC版本核心板的话就会初始化EMMCinterrupt_init函数,初始化中断initr_enable_interrupts函数,使能中断。initr_ethaddr函数,初始化网络- …
run_main_loop函数,主循环,处理命令。
2134

被折叠的 条评论
为什么被折叠?



