U-boot:自搬移

背景:代码在flash上,但是内存运行得快,所以uboot要自搬移到内存去跑代码

Boot 自搬移是 U-Boot 启动流程中一个核心机制,简单来说就是 U-Boot 将自身从启动时的加载地址,搬运到编译时指定的运行地址,并修正内部地址引用后,在新地址上继续执行 的过程。这个机制是 U-Boot 能灵活适配不同硬件平台、优化内存使用的关键。

一、 为什么需要自搬移?

U-Boot 的启动分为两个阶段,自搬移的需求源于加载地址和运行地址的不一致:

1)加载地址:U-Boot 最初被 BootROM(芯片内置的固化程序)从启动介质(如 SPI Flash、eMMC)加载到内存的低地址区域,这个地址由芯片硬件特性决定(比如很多 ARM 芯片会把 Flash 映射到 0x00000000 地址,U-Boot 被加载到这里执行第一阶段代码)。

2)运行地址:编译 U-Boot 时会通过链接脚本指定一个高地址的内存空间(称为TEXT_BASE),这个地址是 U-Boot 的最优运行地址(通常是 SDRAM 的一片连续、无冲突的空间,能启用 Cache 加速,且不会和内核镜像、设备树的加载地址冲突)。

如果不进行自搬移,U-Boot 只能在狭窄的低地址空间运行,不仅性能受限,还会占用内核镜像的加载区域,导致内核无法正常启动。

二、 U-Boot 自搬移的核心流程

自搬移发生在 U-Boot 第一阶段(SPL,Secondary Program Loader) 初始化关键硬件(如 SDRAM)之后,第二阶段主程序启动之前,具体步骤如下:

1、硬件初始化准备

1)关闭中断:防止搬移过程被打断导致程序崩溃。

2)初始化栈:为搬移函数分配临时栈空间(栈必须在未被搬移覆盖的内存区域)。

3)初始化 SDRAM:这是自搬移的前提------ 只有 SDRAM 初始化完成,才有足够的空间存放搬移后的 U-Boot。

2、计算搬移参数

1)确定源地址(Src):U-Boot 当前的加载地址(可通过链接脚本符号或硬件寄存器获取)。

2)确定目的地址(Dst):编译时指定的TEXT_BASE(运行地址,在 SDRAM 中)。

3)确定搬移长度(Len):U-Boot 镜像的总长度(通过链接脚本中的__end - __start计算)。

3、执行内存拷贝(搬移操作)

1)调用内存拷贝函数(通常是汇编实现的高效memcpy),将 U-Boot 从源地址完整拷贝到目的地址。

2)关键注意点:如果源地址和目的地址存在内存重叠(如Dst < Src + Len),必须从高地址向低地址拷贝,避免未拷贝的内容被提前覆盖。

4、重定位修正(最核心的步骤)

1)U-Boot 中存在大量绝对地址引用(如全局变量、函数指针、跳转指令),这些地址在编译时基于TEXT_BASE生成,但搬移前指向的是源地址空间。自搬移后必须修正这些地址,否则程序会跳转到错误的位置执行。

2)读取编译时生成的重定位表(Relocation Table):该表记录了所有需要修正的绝对地址的位置和偏移量。

3)遍历重定位表,对每个绝对地址执行修正:修正后地址 = 原地址 + 目的地址 - 源地址

4)修正全局偏移表(GOT)、函数指针等关键数据结构。

5、跳转到新地址执行

1)修正程序计数器(PC),跳转到目的地址的 U-Boot 入口函数(通常是board_init_r)。

2)此时 U-Boot 正式在TEXT_BASE地址运行,后续所有操作都基于新地址空间。

3)可选:将原地址空间的内容清空,释放内存给内核或其他程序使用。

三、 自搬移的关键技术细节

1、链接脚本的作用

U-Boot 的自搬移依赖链接脚本(如u-boot.lds)的精准配置,主要定义:

1)TEXT_BASE:运行地址(如0x80800000)。

2)代码段(.text)、数据段(.data)、BSS 段(.bss)的地址范围。

3)重定位表的起始和结束地址(__rel_dyn_start、__rel_dyn_end)。

2、与芯片架构的关联

1)ARM 架构:自搬移逻辑通常在arch/arm/lib/relocate.S中实现,依赖 ARM 的异常向量表、PC 寄存器操作。

2)RISC-V 架构:逻辑类似,但地址修正规则和寄存器操作与 ARM 不同,对应代码在arch/riscv/lib/relocate.S。

3)对于你接触的瑞芯微 RK3506/RK3576(ARM 架构),移植 U-Boot 时需重点确认TEXT_BASE是否与芯片的 SDRAM 地址空间匹配。

3、自搬移的异常排查

自搬移失败是 U-Boot 移植中常见的问题,典型现象是 U-Boot 第一阶段执行后卡死,常见原因:

1)TEXT_BASE设置错误(超出 SDRAM 地址范围)。

2)重定位表生成不完整(编译时未启用-ffunction-sections等参数)。

3)内存拷贝时发生地址重叠,且拷贝方向错误。

4)SDRAM 初始化不完整(如时序配置错误,导致搬移后的数据损坏)。

四、 特殊场景:无自搬移的 U-Boot

并非所有场景都需要自搬移,比如:

1)加载地址 = 运行地址:如果 U-Boot 直接被加载到TEXT_BASE指定的地址(如通过 JTAG 烧写至 SDRAM 运行),则无需搬移。

2)片内 RAM 运行的 U-Boot SPL:SPL 通常体积很小,直接在芯片的片内 RAM 运行,无需搬移。

相关推荐
阿萨德528号2 小时前
Spring Boot + WebSocket超简单实战源码(前后端实时交互)
spring boot·websocket·交互
JiMoKuangXiangQu2 小时前
Linux 内存 domain 管理
linux·内存管理·domain
warton882 小时前
ubuntu24下操作配置mysql8相关目录到指定地址
linux·运维·mysql
小亮亮虫2 小时前
linux-交叉编译链安装
linux
学Linux的语莫2 小时前
本地部署ollama
linux·服务器·langchain
`林中水滴`2 小时前
Linux系列:Linux 安装 MySQL 5.7.27 教程
linux·mysql
麦兜*2 小时前
Spring Boot 日志配置 + Logback vs Log4j2 性能对比 + 选型建议
spring boot·log4j·logback
牧小七2 小时前
springboot配置maven激活配置文件
spring boot·后端·maven
m0_738120722 小时前
应急响应——知攻善防蓝队溯源靶机Linux-2详细流程
linux·服务器·网络·安全·web安全·php