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 运行,无需搬移。

相关推荐
琥珀色糖2 小时前
Linux守护进程
linux·终端·守护进程·会话·进程组
行百里er4 小时前
Gateway 上别硬塞 MVC:DeferredImportSelector 看菜下锅
spring boot·后端·开源
黑马程序员毕设5 小时前
基于Java的医院药品管理系统的优化设计与实现
java·开发语言·spring boot·小程序·架构·课程设计·毕设
开心大爆炸6 小时前
xrdp 连接 登录对话框输入密码后闪退
linux·运维·服务器
oushaojun26 小时前
大厂 C++ 面试:深度剖析 Linux Signal 信号机制(转)
linux
xcl09256 小时前
酒馆预约系统开发实战:从需求分析到上线全流程指南
java·spring boot·需求分析
wxwx_bscxy3227 小时前
基于springboot宠物领养系统的设计与实现
数据库·spring boot·后端·spring·宠物
苏生Susheng7 小时前
【软件实施】Linux系统Shell脚本教程
linux·运维·服务器·chrome·spring boot·学习·实施
Ruiery7 小时前
Linux 6.6内核 IOMMU 深度解析(七):DMA API 与 IOMMU 集成 — 从 dma_map_single 到 iommu_map
linux·运维·服务器
分支预测失败7 小时前
RISC-V AIA 中断架构实战:从 PLIC 到 APLIC 与 IMSIC 的迁移
linux·后端