【源码分析】Uboot启动流程详细分析(二)

笔者把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函数设置gdmon_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->baudrate
  • serial_init,初始化串口
  • console_init_f,设置gd->have_console1,表示有个控制台,此函数也将前面暂存在缓冲区中的数据通过控制台打印出来
  • display_optionsdisplay_text_infoprint_cpuinfoshow_board_info都是打印一些信息
  • init_func_i2c函数用于初始化I2C
  • dram_init,由于I.MX6ULL是在bootrom的时候就初始化好DDR的,所以此处没啥太大意义

6.3 第三阶段:内存分配(用于uboot重定位)

还是common/board_f.c中的初始化序列 init_sequence_f中的一系列初始化函数

  • setup_dest_addr,设置gd->ram_sizegd->ram_topgd->relocaddr 这三个的值。接下来我们会遇到很多跟数值有关的设置,此时relocaddr == ram_top

  • reserve_round_4k 函数用于对 gd->relocaddr4KB对齐,但是原来就已经对齐了,相当于没用

  • reserve_mmu,留出 MMUTLB表的位置,分配MMUTLB表内存以后会对gd->relocaddr64K 字节对齐。

  • reserve_uboot, 留出重定位后的uboot所占用的内存区域,uboot所占用大小由 gd中的mon_len 所指定,留出uboot的空间以后还要对gd->relocaddr4K字节对齐,并引入gd->start_addr_sp(后续还会更改这个值)

  • reserve_malloc,留出 malloc 区域,调整gd->start_addr_sp 位置

  • reserve_board 函数,留出板子bd所占的内存区,bd是结构体bd_tbd_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版本核心板的话就会初始化 EMMC
  • interrupt_init 函数,初始化中断
  • initr_enable_interrupts 函数,使能中断。
  • initr_ethaddr 函数,初始化网络
  • run_main_loop函数,主循环,处理命令。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值