U-boot重定位分析
1 U-boot启动方式
u-boot 一般是加到内存的最高端
1.1 NOR 启动
- nor flash 通常映射到 0地址
- 访问模式与内存相同,cpu 直接通过地址访问
- 可以片上执行,不一定要将代码copy到内存上执行
- 价格贵
1.2 NAND 启动
- 串行访问,不能片上执行
- 上电时将 NAND flash的4K copy到CPU的 SRAM,然后SRAM映射到 0地址,最后将SRAM中的数据 copy到 SDRAM 内存中
2 U-boot编译过程
3 U-boot镜像依赖关系
4 U-boot启动流程
参考u-boot.lds, 汇编程序默认从代码段开始运行。代码段的第一个函数,就是reset函数。
- Arch/arm/lib/vector.:b reset
- Arch/arm/cpu/armv7/tart.:bl _main
- Arch/arm/lib/crt0.:b relocate_code
- Arch/arm/lib/relocate.
5 重定位之前的准备工作
5.1 start.S:
- 设置CPU为SVC模式
- 关闭cache、关闭MMU
- 设置关门狗、屏蔽中断、设置时钟、初始化SDRAM
5.2 crt0.S:
- 初始化C语言运行环境、堆栈设置
- 板级各种初始化、初始化NAND、SDRAM
- 初始化全局结构体变量GD、在GD里保存u-boot实际加载地址
- 调用relocate_code,将u-boot镜像从flash拷贝到内存
- 从Flash跳到RAM空间继续执行程序
- BSS段清零、板级初始化、跳入bootcmd或main_loop循环
6 重定位
6.1 在relocate.S文件中
- 将代码段、数据段从Flash搬运到RAM
- 根据动态重定向符号表,对代码进行重定位
6.2 不同版本u-boot重定位
6.2.1 旧版本u-boot重定位
旧版本重定位判断:当前运行地址==链接地址?
非SDRAM启动(不相等),则需要重定位
6.2.2 新版本重定位
都需要重定位
根据SDRAM自动计算出加载地址:实际加载地址==链接地址?
更大程度适配不同硬件平台、启动方式、链接地址
7 如何自动计算加载地址?
7.1 全局数据GD
global data
- 计算实际加载地址:gd->relocaddr =
DRAM的最高端地址- sizeof(log buffer) - siezeof(tlb table) - sizeof(lcdmem)
详情请研究对应的汇编文件 - 用 relocate_code , 将u-boot 拷贝到内存,
然后计算重定位偏移,gd-> reloc_off = 加载地址 - 链接地址 - 从 NOR Flash/SRAM 跳转到内存里执行
adr lr, here
ldr r0, [r9, #GD_RELOC_OFF] /* ro = gd->reloc_off */
add lr, lr, r0
/* 这里不使用bl,不会刷新lr寄存器, 跳转返回后,将lr赋值给pc指针 即here + gd->reloc_off */
b relocate_code
here:
8 relocate_code函数细节
启动mmu之前, 汇编程序的
链接地址=加载到内存中的地址=运行地址
8.1 u-boot 的动态链接技术
U-boot启动前期为什么可以直接在0x0起始地址运行?
- 位置无关代码 + 符号表(浅绿色) +重定位符号表(紫蓝色)
- 基址重置:R_ARM_RELATIVE (0x17 对应重定位表)
8.2 程序加载
具体汇编代码讲解,请看视频
8.3 重定位
具体汇编代码讲解,请看视频