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

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

3天内不再提示

硬核拆解:U-Boot 的第一条指令到底做了什么?

jf_44130326 来源:Linux1024 作者:Linux1024 2026-04-26 07:08 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

嵌入式Linux的朋友,大概率都有过这样的体验:烧录完U-Boot,插上串口,看着屏幕上弹出U-Boot 202x.xx的打印信息,心里就踏实了——系统活了。

但很少有人想过,从芯片通电到这句打印出现,背后已经悄悄跑过了成千上万条指令。而这一切的起点,也是最神秘、最底层的那一步,就藏在arch/arm/cpu/armv8/start.S这个文件里。

今天,我们就逐帧拆解这份ARMv8架构下U-Boot的“启动基因”,搞懂从通电到进入C语言世界(_main函数)之前,CPU到底在忙些什么。

(建议收藏,调试启动问题时,这篇就是你的“救命指南”)

wKgZO2ntScqATmouAAFMQICUmDU771.png

一、一切的起点:_start标号

整个U-Boot的启动,始于一个全局标号_start,这是芯片上电/复位后,PC指针(程序计数器)指向的第一个地址,相当于U-Boot的“出生证明”。

在_start开头,有一段非常关键的条件编译,给SoC厂商留足了“自定义空间”:

#ifdefCONFIG_ENABLE_ARM_SOC_BOOT0_HOOK#include#else  b  reset#endif

简单说:有些芯片要求引导头必须包含特殊签名或头部结构,厂商就可以在boot0.h里做定制化操作;如果不需要,就直接跳转到reset标号,进入下一步。

这一步看似简单,却是U-Boot适配不同芯片的关键“后门”。

二、位置无关:U-Boot能“随处运行”的秘密

现代U-Boot有个很强大的特性——位置无关代码(PIC),也就是说,它的链接地址(编译时指定的地址)和实际加载地址(烧录到芯片的地址)可以不一样,怎么烧录都能正常启动。

这个特性的核心,就藏在pie_fixup这段代码里:

pie_fixup:  adr x0, _start     // 读取 _start 的运行时实际地址  ldr x1, _TEXT_BASE   // 读取编译时指定的链接地址  sub x9, x0, x1     // 计算实际地址与链接地址的偏移量  ...pie_fix_loop: // 遍历重定位表,给所有需要修正的地址加上偏移量

逻辑很直白:先算出“实际地址”和“预期地址”的差值(偏移量),再遍历整个重定位表,把所有需要重定位的位置都加上这个偏移量。

正是这几步操作,让U-Boot实现了“任意地址加载,随处运行”,极大降低了烧录和调试的门槛。

三、异常级别切换:从EL3降到EL1的“降权”操作

ARMv8架构的CPU有4个异常级别(EL0~EL3),级别越高,权限越大。芯片上电时,通常会处于最高权限的EL3,但Linux内核一般只需要运行在EL1(或EL2,用于虚拟化)。

所以,start.S要做的关键一步,就是把CPU的异常级别“降下来”,用一个精妙的宏就能完成统一设置:

adrx0, vectorsswitch_elx1,3f,2f,1f

这段代码的作用是:判断当前CPU的异常级别,然后执行对应级别的初始化:

EL3(最高级别):设置向量表基地址(vbar_el3),配置SCR_EL3寄存器,开启FP/SIMD功能(浮点/向量运算)。

EL2(虚拟化级别):设置vbar_el2,同样开启FP/SIMD。

EL1(内核级别):设置vbar_el1。

无论从哪个级别启动,最后都会统一落到同一个入口,同时初始化通用定时器频率(cntfrq_el0),为后续的驱动和计时功能提供精准时钟

四、开启缓存+多核“唤醒”:让系统“跑起来”

芯片上电时,缓存(ICache/DCache)是默认关闭的——缓存虽能提升性能,但启动初期系统状态混乱,开启缓存会导致数据异常。所以U-Boot会在这里手动开启缓存:

#ifndefCONFIG_SYS_ICACHE_OFF  mov x1, #CR_I // 开启 ICache#else  mov x1, #0  // 关闭 ICache#endif

然后根据当前异常级别,将配置写入对应的SCTLR_ELx寄存器,同时清除中断掩码(DAIF),让系统能响应SError(系统错误)。

如果是多核处理器(比如Cortex-A53/A57),还要开启SMP一致性(多核协同工作的关键):

mrsx0, S3_1_c15_c2_1orr x0, x0,#0x40 // 置位 SMPEN 位msr S3_1_c15_c2_1, x0

这一步,就是让多核CPU从“各自为战”变成“协同工作”的基础。

五、硬件“补丁”:修复ARM处理器的Errata

哪怕是ARM这样的巨头,其处理器也可能存在一些底层bug(行业内叫Errata),这些bug可能导致特定场景下的数据不一致、死锁或性能异常,需要通过固件补丁来修复。

start.S中的apply_core_errata函数,就是干这个活的,由Kconfig中的CONFIG_ARM_ERRATA_*选项控制,针对Cortex-A57等处理器的经典Errata打补丁:

Errata 828024:关闭write-back no-allocate的non-allocate hint,避免数据缓存异常。

Errata 826974:关掉DMB指令前的投机执行,防止指令执行顺序错乱。

Errata 833471 / 829520 / 833069:调整分支预测器、FPSCR寄存器刷新等行为,提升稳定性。

这些看似晦涩的寄存器操作,每一步都是为了让处理器更稳定、更可靠。

六、多核“点名”:主CPU唤醒所有副CPU

完成底层配置后,就到了板级初始化的第一站——lowlevel_init,主要干三件核心事:

1.主CPU初始化GIC中断控制器(Distributor和CPU Interface),相当于给系统“装中断管家”。

2.如果开启了MULTIENTRY(多核启动),副CPU会先等待主CPU释放“自旋表”地址,然后切换到对应异常级别,等待主CPU调度。

3.主CPU继续执行,走向master_cpu标号。

这里有个很巧妙的设计:smp_kick_all_cpus函数会通过GIC分发SGI 0号软中断,把所有副CPU“踢醒”,让它们进入U-Boot启动流程。副CPU则在slave_cpu标号下“待命”,一旦检测到CPU_RELEASE_ADDR非零,就立即跳转执行。

这就是U-Boot多核启动的核心逻辑——主CPU “点名”,副CPU “应答”,协同启动。

七、终章:跳入C语言世界,奔向_main

当所有底层配置、多核唤醒都完成后,主CPU就会执行关键的一步,跳入C语言的世界:

master_cpu:  bl _main

至此,start.S的使命就暂告一段落了。

接下来的工作,就交给arch/arm/lib/crt0.S和board_init_f/board_init_r完成:重定位U-Boot代码、清除BSS段、初始化串口、DRAM(内存)、外设,最终才能看到我们熟悉的U-Boot打印信息。

写在最后

回看这份start.S,它就像一颗经过精密雕琢的钻石——没有多余的指令,每一个条件编译、每一次寄存器操作,都是为了把上电时混乱的系统初态,梳理成一个干净、稳定的运行环境。

它不仅是U-Boot的启动起点,更是理解整个ARMv8系统启动流程的“最佳教科书”。

如果你在调试嵌入式系统时,遇到“卡在启动早期”“多核不同步”“打开缓存就挂死”等问题,不妨回到这份代码里找找答案——真正的宝藏,往往就藏在最开始的地方。

最后,留言区聊聊:你在调试U-Boot启动时,遇到过最头疼的问题是什么?

审核编辑 黄宇

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

    关注

    0

    文章

    140

    浏览量

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

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    深度解析 RK 平台 U-Boot 环境变量(env):原理、配置与实战

    环境变量(env)是 U-Boot 的核心配置机制,无需重新编译即可灵活调整启动参数。在 Rockchip(RK)平台上,环境变量不仅继承了 U-Boot 的通用特性,还针对 RK 芯片架构做了大量
    的头像 发表于 04-27 07:11 522次阅读
    深度解析 RK 平台 <b class='flag-5'>U-Boot</b> 环境变量(env):原理、配置与实战

    深度剖析U-Boot ADC Uclass:从架构到实战的全维度解析

    、数据流到实战开发,全方位拆解 U-Boot ADC Uclass 的设计精髓,帮你吃透这核心子系统。 、架构概览:三层架构,职责分明 U-Bo
    的头像 发表于 04-26 07:08 45次阅读
    深度剖析<b class='flag-5'>U-Boot</b> ADC Uclass:从架构到实战的全维度解析

    S32G398 u-boot OCOTP 编程保险丝仅在复位后激活是为什么?

    cmp\' 失败,但在\'reset\'后成功。 有没有另种方法可以在同 u-boot 会话中更新 efuse 值?
    发表于 04-08 06:05

    更新 U-boot 时出现的问题求解

    我在尝试更新 U-boot 时遇到问题。最初我无法启动 Fedora,但后来我读到了这并尝试更新 U-boot。但是,当我按照官方文档我卡在迷你机屏幕上,什么也做不了。我担心董事会来了 DOA......
    发表于 04-01 07:20

    更新固件后 U-boot 不运行怎么解决?

    该如何修复它?我正在使用 screen 和 sx 通过 xmodem 对 u-boot 固件进行编程。传输完成后,我看到打印了堆点。这正常吗?xmodem 是否对数据进行校验和以确保正确接收数据? 这里有些图片:
    发表于 03-25 08:17

    更新 SPL 和 U-Boot的提示和技巧

    U-Boot 和 SPL 文件并将它们加载到 U 盘上 7 连接将 USB 记忆棒连接到 VF2 板并将其安装在文件夹中 8 更新来自终端的固件 9 验证使用命令 cat /proc/mtd 并检查如下
    发表于 03-20 08:15

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

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

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

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

    U-Boot SPL核心文件spl.c深度解析:从启动流程到调试优化

    在嵌入式系统开发中,U-Boot 的 SPL(Secondary Program Loader)扮演着至关重要的角色,它是系统上电后执行的第一个软件组件之,负责为后续启动过程铺平道路。本文将深入
    的头像 发表于 02-05 14:08 525次阅读
    <b class='flag-5'>U-Boot</b> SPL核心文件spl.c深度解析:从启动流程到调试优化

    深入解析U-Boot TPL代码:嵌入式启动的“第一棒”背后的秘密

    在嵌入式系统启动过程中,从按下电源键到操作系统开始运行,中间藏着系列精密的初始化步骤。今天我们就来拆解 Rockchip 平台 U-Boot 中的 TPL(Tiny Program Loader)阶段核心代码tpl.c,看看这
    的头像 发表于 02-05 14:07 1314次阅读
    深入解析<b class='flag-5'>U-Boot</b> TPL代码:嵌入式启动的“<b class='flag-5'>第一</b>棒”背后的秘密

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

    在嵌入式系统开发中,U-Boot 作为主流的引导加载程序,其命令处理、交互逻辑和自动启动流程是核心功能模块。本文将围绕command.c、cli.c和autoboot.c三个关键文件,从核心
    的头像 发表于 02-03 15:44 1008次阅读
    深入解析<b class='flag-5'>U-Boot</b>命令处理核心文件:功能、调试与开发价值

    深入解析U-Boot核心文件board_f.c:知识点、调试要点与开发价值

    在嵌入式系统开发中,U-Boot 作为应用最广泛的引导程序,其底层初始化逻辑直接决定了硬件启动的稳定性与可靠性。
    的头像 发表于 02-03 15:38 873次阅读
    深入解析<b class='flag-5'>U-Boot</b>核心文件board_f.c:知识点、调试要点与开发价值

    解析Rockchip平台U-Boot核心文件:boot_rkimg.c到底做了什么?

    在嵌入式开发中,U-Boot 作为引导程序的 “中流砥柱”,负责初始化硬件、加载内核并启动系统。对于 Rockchip 平台的设备(如常见的开发板、智能终端),boot_rkimg.c 是 U-Boot 中专门处理启动流程的核心
    的头像 发表于 02-03 15:29 986次阅读
    解析Rockchip平台<b class='flag-5'>U-Boot</b>核心文件:<b class='flag-5'>boot</b>_rkimg.c<b class='flag-5'>到底</b><b class='flag-5'>做了</b>什么?

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

    的启动代码,拆解 RK3506 平台 U-Boot 重定位的实现逻辑、关键步骤与底层原理。 路径:u-boot/arch/arm/cpu/armv7/start.S 、重定位的
    的头像 发表于 11-28 07:05 1019次阅读
    深入理解 RK3506 <b class='flag-5'>U-Boot</b> 重定位:从代码到原理

    U-Boot 无法识别 NAND怎么解决?

    U-Boot 无法识别 NAND
    发表于 09-03 06:37