0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

深入理解 RK3506 U-Boot 重定位:从代码到原理

jf_44130326 来源:Linux1024 作者:Linux1024 2025-11-28 07:05 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

嵌入式系统中,U-Boot作为引导加载程序,其启动流程的核心环节之一就是重定位(Relocation)。对于RK3506这类基于ARM Cortex-A架构的芯片,重定位的本质是将U-Boot代码从初始加载地址(通常是片内ROM或Flash)复制到运行效率更高的片外RAM,再切换执行环境到RAM中运行。

本文将结合U-Boot源码中ARM Cortex核心的启动代码,拆解RK3506平台U-Boot重定位的实现逻辑、关键步骤与底层原理。

路径:u-boot/arch/arm/cpu/armv7/start.S

wKgZPGko2kqAGNWAAAck-TkUqlU013.png

一、重定位的核心目的:为何需要“搬家”?

RK3506的U-Boot启动初期,代码通常从片内BootROMSPI Flash加载到片内SRAM(小容量高速内存)执行。但SRAM容量有限(通常仅几十KB),无法容纳完整的U-Boot镜像(包含驱动、命令、文件系统等模块),也无法满足后续加载Linux内核的需求。

重定位的核心目标:

1.释放存储空间:将U-Boot完整镜像从Flash/SRAM迁移到大容量片外DDR内存;

2.提升执行效率:DDR内存带宽更高、容量更大,支持U-Boot运行复杂逻辑(如设备初始化、内核加载);

3.预留内存空间:为Linux内核、设备树等后续加载的镜像预留连续内存区域。

二、重定位的前提:启动初期的关键初始化

在执行重定位前,U-Boot必须完成一系列底层初始化,为“搬家”做好准备。结合本文提供的ARM Cortex启动代码,这些准备工作主要集中在reset入口函数中:

1.模式与中断初始化

reset:  b  save_boot_paramssave_boot_params_ret:  /* 切换到 SVC32 模式,禁用 FIQ/IRQ */  mrs r0, cpsr  and r1, r0,#0x1f    @ 掩码模式位  teq r1,#0x1a       @ 检查是否为 HYP 模式  bicne r0, r0,#0x1f    @ 清除模式位  orrne r0, r0,#0x13    @ 设置为 SVC 模式(管理模式)  orr r0, r0,#0xc0     @ 禁用 FIQ (0x80) 和 IRQ (0x40)  msr cpsr, r0

•切换到ARM特权模式(SVC32):确保U-Boot拥有访问系统寄存器、修改内存配置的权限;

•禁用中断:避免初始化过程中被外部中断打断,导致系统异常。

2.向量表初始化

/* 设置 VBAR 寄存器,指向 U-Boot 向量表 */ldr r0, =_startmcr p15,0, r0, c12, c0,0 @ 写入VBAR(向量表基地址寄存器)

•ARMv7架构通过VBAR寄存器指定异常向量表地址;

•重定位前,向量表位于初始加载地址(如SRAM),后续重定位后需确保向量表地址同步更新(由链接脚本配合处理)。

3.缓存与MMU初始化(cpu_init_cp15

重定位前需禁用MMU(内存管理单元)和缓存,避免地址映射干扰内存复制:

ENTRY(cpu_init_cp15) /* invalidate L1 I/D 缓存、TLB */  mov r0,#0  mcr p15,0, r0, c8, c7,0 @ invalidate TLBs  mcr p15,0, r0, c7, c5,0 @ invalidate I-cache /* 禁用 MMU、缓存相关配置 */  mrc p15,0, r0, c1, c0,0  bic r0, r0,#0x00002000  @ 清除 V 位(向量表地址偏移)  bic r0, r0,#0x00000007  @ 清除 CAM 位(缓存相关)  orr r0, r0,#0x00000800  @ 启用 BTB(分支预测)#ifdef CONFIG_SYS_ICACHE_OFF  bic r0, r0,#0x00001000  @ 禁用 I-cache#else  orr r0, r0,#0x00001000  @ 启用 I-cache(重定位后生效)#endif  mcr p15,0, r0, c1, c0,0

•初始化CP15寄存器(ARM系统控制寄存器),清空缓存和TLB(地址转换缓存);

•禁用MMU:此时CPU访问的是物理地址,确保内存复制过程中地址无映射偏差;

•按需启用I-cache(指令缓存):重定位后代码在DDR中运行时,缓存可提升执行效率。

4.板级底层初始化(cpu_init_crit

ENTRY(cpu_init_crit) b lowlevel_init    @ 跳转到板级初始化ENDPROC(cpu_init_crit)

•lowlevel_init是RK3506平台的板级初始化函数(由瑞芯微适配);

•核心任务:初始化DDR内存控制器、配置PLL时钟(提升DDR带宽)、初始化SPI Flash等外设;

•关键:只有完成DDR初始化,U-Boot才能将自身复制到DDR中,这是重定位的硬件基础

三、重定位的核心实现:_main函数的“搬家”逻辑

当底层初始化(尤其是DDR初始化)完成后,代码通过bl _main跳转到U-Boot核心初始化流程,重定位的核心逻辑就在_main函数中(位于common/main.c)。

结合RK3506的平台特性,_main函数中重定位的关键步骤如下:

1.确定重定位地址(链接脚本定义)

U-Boot的重定位目标地址由链接脚本(如arch/arm/cpu/armv7/rk3506/u-boot.lds)定义,核心符号:

•_start:U-Boot初始加载地址(SRAM或Flash地址);

•__image_copy_start:镜像复制起始地址(初始加载地址的代码段起始);

•__image_copy_end:镜像复制结束地址;

•__bss_start/__bss_end:BSS段起始/结束地址(重定位后需清零);

•CONFIG_SYS_TEXT_BASE:重定位目标地址(RK3506通常配置为DDR起始地址,如0x80000000)。

2.内存复制:从初始地址到DDR

重定位的核心操作是逐字节复制U-Boot镜像到DDR目标地址,代码逻辑简化如下:

// 简化自 common/main.cvoid_main(void) { // 1. 获取链接脚本定义的地址符号 externulong__image_copy_start, __image_copy_end; externulong__bss_start, __bss_end; ulongdst = CONFIG_SYS_TEXT_BASE; // 重定位目标地址(DDR) ulongsrc = (ulong)&__image_copy_start; // 源地址(SRAM/Flash) // 2. 只有当源地址 != 目标地址时,才需要复制(避免自身覆盖) if(src != dst) {    memcpy((void*)dst, (void*)src, &__image_copy_end - &__image_copy_start);  } // 3. 清零 BSS 段(未初始化全局变量)  memset((void*)&__bss_start,0, &__bss_end - &__bss_start); // 4. 跳转到 DDR 中的 U-Boot 继续执行  board_init_f_r_trampoline(dst);}

复制范围:从__image_copy_start到__image_copy_end,包含代码段(.text)、数据段(.data)等已初始化部分;

避免自身覆盖:若源地址与目标地址重叠(如部分SRAM与DDR地址重叠),U-Boot会先复制不重叠部分,再处理重叠区域,防止复制过程中覆盖未复制的代码;

BSS段清零:BSS段存储未初始化全局变量,C语言标准要求其初始值为0,因此重定位后需手动清零。

3.跳转至DDR执行:地址切换

复制完成后,通过board_init_f_r_trampoline函数跳转到DDR中的U-Boot代码继续执行。此时CPU执行的指令已从DDR读取,重定位完成。

4.栈指针更新

重定位后,栈指针(SP)也需更新到DDR中的安全地址(避免使用SRAM栈导致溢出),由board_init_f函数初始化:

// 简化自 common/board_f.cvoidboard_init_f(ulongboot_flags){ ulongsp = CONFIG_SYS_INIT_SP_ADDR; // DDR 中的栈地址  sp -=sizeof(structglobal_data); // 预留全局数据结构空间  gd = (structglobal_data *)sp;  memset(gd,0,sizeof(structglobal_data)); // 初始化栈指针 asmvolatile("mov sp, %0": :"r"(sp) : "memory"); // 后续初始化:设备树加载、命令初始化、内核引导等}

•CONFIG_SYS_INIT_SP_ADDR:RK3506配置为DDR中的一段连续地址,确保栈空间足够;

•global_data:U-Boot全局数据结构,存储系统状态(如内存布局、设备信息),重定位后需在DDR中重新初始化。

四、重定位后的关键处理

1.向量表同步更新

重定位后,向量表地址需同步更新到DDR中的新地址,避免异常处理时跳转到旧地址(SRAM/Flash)。由于之前已通过VBAR寄存器设置向量表基地址为_start,而_start在重定位后指向DDR地址,因此无需额外修改(链接脚本确保_start对应DDR目标地址)。

2.缓存重新配置

重定位完成后,U-Boot会重新启用I-cache/D-cache(若配置),提升执行效率。此时MMU仍处于禁用状态(直到Linux内核启动时启用),CPU直接访问DDR物理地址。

3.避免重定位后的地址错误

•所有全局变量、函数指针均使用位置无关代码(PIC)编译,确保重定位后地址正确映射;

•链接脚本通过TEXT_BASE强制指定目标地址,确保复制后的镜像在DDR中地址对齐。

五、RK3506重定位的特殊注意事项

1.DDR初始化优先级:RK3506的DDR控制器初始化是重定位的前提,需通过lowlevel_init配置DDR时序、电压,确保DDR稳定工作;

2.Flash访问兼容性:若初始加载地址为SPI Flash(如0x10000000),复制时需通过RK3506的SPI控制器驱动读取Flash数据,再写入DDR;

3.内存布局优化:RK3506的DDR起始地址通常为0x80000000,U-Boot重定位后,会在DDR中预留后续加载Linux内核(如0x80200000)和设备树(如0x80100000)的空间,避免地址冲突。

六、总结:重定位的完整流程

RK3506 U-Boot重定位的核心是“初始化硬件→复制镜像→切换执行环境”,完整流程可概括为:

1.复位入口(reset):切换SVC模式、禁用中断、初始化向量表;

2.底层初始化:初始化CP15寄存器(缓存/ MMU)、板级硬件(DDR/PLL);

3.确定地址:通过链接脚本获取源地址、目标地址(DDR);

4.镜像复制:memcpy复制代码段/数据段到DDR,清零BSS段;

5.切换执行:更新栈指针,跳转到DDR中的U-Boot继续执行;

6.后续初始化:加载设备树、初始化外设、引导Linux内核。

重定位是U-Boot从“小容量初始环境”到“大容量运行环境”的关键一步,理解其原理不仅能帮助排查启动故障(如DDR初始化失败导致重定位失败),也能为定制化U-Boot(如调整内存布局、优化启动速度)提供基础。

对于RK3506开发者,建议结合链接脚本和lowlevel_init代码,重点关注CONFIG_SYS_TEXT_BASE和DDR初始化参数,确保重定位地址与硬件配置一致。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • u-boot
    +关注

    关注

    0

    文章

    135

    浏览量

    39920
  • RK3506
    +关注

    关注

    0

    文章

    100

    浏览量

    997
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    米尔RK3506 DSMC实战,Local Bus高速互联

    在工业控制场景中,芯片间的高速数据交互是一个核心需求。传统方案要么依赖串口/网络等低速通道,要么需要昂贵的共享内存架构。米尔RK3506核心板的DSMC接口提供了一种新选择——通过LocalBus
    的头像 发表于 04-16 08:06 4190次阅读
    米尔<b class='flag-5'>RK3506</b> DSMC实战,Local Bus高速互联

    瑞芯微RK3506 Flexbus技术开发指南,原理、内核配置测试的完整攻略

    基于触觉智能的RK3506核心板/开发板,介绍FlexBus总线的技术架构、设备树配置、驱动实现与测试方法,为嵌入式开发者提供理论到实战的一站式指南。如需开发板评估
    的头像 发表于 03-14 07:24 514次阅读
    瑞芯微<b class='flag-5'>RK3506</b> Flexbus技术开发指南,<b class='flag-5'>从</b>原理、内核配置<b class='flag-5'>到</b>测试的完整攻略

    深入解析U-Boot image.c:RK平台镜像处理核心逻辑

    的SD/NAND/SPI等启动方式做了专属适配。本文将拆解image.c的核心逻辑,梳理RK平台镜像处理的关键流程,帮助开发者理解和调试启动相关问题。 一、文件定位与核心作用 image.c是
    的头像 发表于 02-24 16:46 1768次阅读
    <b class='flag-5'>深入</b>解析<b class='flag-5'>U-Boot</b> image.c:<b class='flag-5'>RK</b>平台镜像处理核心逻辑

    深入解析RK3588 U-Boot板级文件:evb_rk3588.c核心逻辑拆解

    在嵌入式开发领域,瑞芯微RK3588凭借超强的算力、丰富的接口和广泛的场景适配性,成为高端边缘计算、消费电子项目的热门选择。而U-Boot作为嵌入式系统的“第一道门”,负责硬件初始化、引导内核启动,其板级适配代码直接决定了芯片硬
    的头像 发表于 02-24 15:24 956次阅读
    <b class='flag-5'>深入</b>解析<b class='flag-5'>RK</b>3588 <b class='flag-5'>U-Boot</b>板级文件:evb_<b class='flag-5'>rk</b>3588.c核心逻辑拆解

    深入解析U-Boot命令处理核心文件:功能、调试与开发价值

    知识点、调试关注点和开发意义三方面展开分析,并通过流程图展示它们的协作机制,帮助开发者深入理解 U-Boot 的命令系统。
    的头像 发表于 02-03 15:44 980次阅读
    <b class='flag-5'>深入</b>解析<b class='flag-5'>U-Boot</b>命令处理核心文件:功能、调试与开发价值

    深入解析rk平台Android Bootloader核心代码启动流程AVB验证

    下android_bootloader.c的核心代码,带你读懂Android设备Bootloader内核的完整启动逻辑,以及开发者关注这些代码的核心价值。 一、
    的头像 发表于 01-22 07:06 465次阅读
    <b class='flag-5'>深入</b>解析<b class='flag-5'>rk</b>平台Android Bootloader核心<b class='flag-5'>代码</b>:<b class='flag-5'>从</b>启动流程<b class='flag-5'>到</b>AVB验证

    RK3506 MIPI转HDMI显示开发实战:硬件驱动全解析

    0 入门 Linux 嵌入式开发!RK3506 开发板实战教程系列开篇 在嵌入式设备开发中,MIPI DSI接口(移动行业处理器接口)广泛用于连接LCD屏,而HDMI则是高清显示输出的主流标准
    的头像 发表于 01-06 07:09 1065次阅读
    <b class='flag-5'>RK3506</b> MIPI转HDMI显示开发实战:<b class='flag-5'>从</b>硬件<b class='flag-5'>到</b>驱动全解析

    技术分享 | RK3506如何交叉编译frp wireguard

    RK3506拥有着不错的性价比以及与之相匹配的性能优势,非常适合用来做边缘计算网关、小型数据收集端点等。今天给大家带来两款内网穿透工具的交叉编译移植,方便在RK3506上搭建相关应用。在编译两个工具
    的头像 发表于 12-25 17:29 778次阅读
    技术分享 | <b class='flag-5'>RK3506</b>如何交叉编译frp wireguard

    如何让RK3506流畅刷图,用好RGA?

    本文基于触觉智能RK3506核心板/开发板,介绍RGAIM2D进行图像处理,包括相关编译与测试方法。
    的头像 发表于 10-29 10:00 1505次阅读
    如何让<b class='flag-5'>RK3506</b>流畅刷图,用好RGA?

    RK3506开发板Linux开发板极致性价比之选

    RK3506开发板Linux开发板极致性价比之选瑞芯微RK3506开发板,3核Cortex-A7@1.5GHz+Cortex-M0,Linux+RT-Thread系统支持,128MB超大
    的头像 发表于 09-11 16:26 3840次阅读
    <b class='flag-5'>RK3506</b>开发板Linux开发板极致性价比之选

    【米尔RK3506国产开发板评测试用】开箱体体验

    很高兴今天收到了米尔科技的RK3506开发板,下面是开箱体验,后期的测试使用中将会做详细的测试和试用。 1.开箱,包含以下: RK3506开发板1 USB_TYPEC1 10Pin连接端子1 快速
    发表于 07-30 01:06

    有奖丨米尔 瑞芯微RK3506开发板免费试用来啦!

    米尔与瑞芯微合作发布的新品基于瑞芯微RK3506应用处理器的MYD-YR3506开发板免费试用名额增加啦
    的头像 发表于 07-10 08:03 1177次阅读
    有奖丨米尔 瑞芯微<b class='flag-5'>RK3506</b>开发板免费试用来啦!

    瑞芯微RK3506 vs NXP i.MX6ULL

    在关键技术国产化浪潮中,国产芯片正以更高性能、更优成本及自主可控优势实现对海外方案的成功替代。今天触觉智能拿出自家新品瑞芯微RK3506核心板(IDO-SOM3506-S1),与线上某款热销
    的头像 发表于 06-19 16:26 1524次阅读
    瑞芯微<b class='flag-5'>RK3506</b> vs NXP i.MX6ULL

    米尔瑞芯微多核异构低功耗RK3506核心板重磅发布

    近日,米尔电子发布MYC-YR3506核心板和开发板,基于国产新一代入门级工业处理器瑞芯微RK3506,这款芯片采用三核Cortex-A7+单核Cortex-M0多核异构设计,不仅拥有丰富的工业接口
    发表于 05-16 17:20

    触觉智能RK3506核心板,工业应用之RK3506 RT-Linux实时性测试

    触觉智能RK3506核心板,工业应用方案分享之RT-Linux实时性测试
    的头像 发表于 04-27 19:27 2225次阅读
    触觉智能<b class='flag-5'>RK3506</b>核心板,工业应用之<b class='flag-5'>RK3506</b> RT-Linux实时性测试