当前位置: 首页 > news >正文

U-Boot启动探秘:从汇编到命令行的奇幻之旅 - 指南

U-Boot启动探秘:从汇编到命令行的奇幻之旅 - 指南

引言

在嵌入式Linux系统中,U-Boot作为最主流的BootLoader,其启动过程犹如一场精心编排的舞台剧,分为上下两个半场。上半场(Stage1)是用汇编语言编写的硬件初始化“序章”,寂静而迅速;下半场(Stage2)则是用C语言构建的软件生态“主剧”,丰富而互动。理解这场“演出”的每一个环节,是进行U-Boot移植、定制和深度调试的基石。本文将带领大家深入U-Boot的源码世界,逐一解析其Stage1与Stage2的核心步骤。


一、 U-Boot的两种模式与两个阶段

在深入细节之前,我们首先回顾U-Boot的宏观架构:


二、 Stage1:汇编世界的奠基礼

Stage1是整个U-Boot的基石,其代码通常位于 cpu/<arch>/start.S 文件中(例如,对于ARM920T,路径为 cpu/arm920t/start.S)。它的目标是构建一个能够运行C代码的最小化环境。

2.1 入口点与链接脚本

一个可执行的映像文件必须有一个唯一的全局入口点。U-Boot通过链接脚本(如 board/smdk2410/u-boot.lds)来定义这个入口。

OUTPUT_ARCH(arm)
ENTRY(_start) // 定义入口点为 _start 符号
SECTIONS
{
. = 0x00000000; // 入口地址在Flash的0地址
.text :
{
cpu/arm920t/start.o (.text) // 确保start.S的代码在最前面
*(.text)
}
// ... 其他段(.rodata, .data, .bss等)
}

TEXT_BASE = 0x33F80000 定义了U-Boot在RAM中运行的基地址,Stage1后期会将自身重定位到此地址执行。

2.2 Stage1 核心步骤详解

1. 设置异常向量表
位于 _start 处,这是CPU上电后执行的第一条指令。

.globl _start
_start: b reset           // 复位异常,跳转到真正的启动代码ldr pc, _undefined_instructionldr pc, _software_interrupt// ... 其他异常向量

当发生任何异常时,CPU会自动跳转到对应的地址执行。

2. 进入SVC模式
复位后,首先将CPU设置为管理模式,此模式拥有最高特权,可以执行所有操作。

mrs r0, cpsr         // 读取当前程序状态寄存器CPSR到r0
bic r0, r0, #0x1f    // 清除模式位
orr r0, r0, #0xd3    // 设置为SVC模式,并禁止IRQ和FIQ中断
msr cpsr, r0         // 写回CPSR

3. 关闭看门狗
看门狗的作用是防止程序死机,但在初始化阶段,我们需要先关闭它,防止其误触发复位。

ldr r0, =pWTCON      // pWTCON为看门狗控制寄存器地址
mov r1, #0x0
str r1, [r0]         // 向控制寄存器写入0,关闭看门狗

4. 屏蔽所有中断
在初始化过程中,不允许被中断打扰。

mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]         // 屏蔽所有主中断

5. 设置CPU时钟与分频
配置CPU核心时钟(FCLK)、AHB总线时钟(HCLK)和APB总线时钟(PCLK)的比例。

ldr r0, =CLKDIVN
mov r1, #3           // 设置分频比,例如 FCLK:HCLK:PCLK = 1:2:4
str r1, [r0]

6. 设置CP15协处理器
CP15用于控制MMU、Cache等系统核心功能。

cpu_init_crit:mov r0, #0mcr p15, 0, r0, c7, c7, 0  // 使ICache和DCache失效mcr p15, 0, r0, c8, c7, 0  // 使TLB失效// 关闭MMU和Cachemrc p15, 0, r0, c1, c0, 0bic r0, r0, #0x00002300     // 清除控制位bic r0, r0, #0x00000087orr r0, r0, #0x00000002     // 对齐检查使能orr r0, r0, #0x00001000     // 使能ICachemcr p15, 0, r0, c1, c0, 0

7. 初始化内存控制器
这是最关键也是最板级相关的一步。通过配置内存控制寄存器,让CPU能够正确地访问SDRAM。代码通常在 board/<board>/lowlevel_init.S 中。

mov ip, lr
bl lowlevel_init    // 调用低级初始化函数,配置内存时序
mov lr, ip
mov pc, lr

8. 设置栈指针并为BSS段清零
C语言的运行需要栈空间。同时,未初始化的全局变量位于BSS段,需要将其初始化为0。

// 栈设置(在RAM中分配空间)
stack_setup:
ldr r0, _TEXT_BASE  // TEXT_BASE = 0x33F80000
sub r0, r0, #CFG_MALLOC_LEN // 分配动态内存区
sub r0, r0, #CFG_GBL_DATA_SIZE // 分配全局数据结构体空间
sub sp, r0, #12     // 设置栈指针sp
// BSS段清零
clear_bss:
ldr r0, _bss_start
ldr r1, _bss_end
mov r2, #0
clbss_l:
str r2, [r0]
add r0, r0, #4
cmp r0, r1
ble clbss_l

9. 跳转到Stage2
至此,C语言运行环境已准备就绪,通过一条简单的指令,跳转到Stage2的C入口函数。

ldr pc, _start_armboot
_start_armboot: .word start_armboot // start_armboot是C函数地址

三、 Stage2:C语言的繁华世界

Stage2的入口函数是 lib_arm/board.c 中的 start_armboot()。从这里开始,世界变得“丰富多彩”。

3.1 初始化函数序列

start_armboot 函数会依次调用一个初始化函数表 init_sequence[],完成一系列基础设置:

init_fnc_t *init_sequence[] = {
cpu_init,        // 进一步的CPU设置
board_init,      // 开发板相关的GPIO、时钟初始化
interrupt_init,  // 初始化中断控制器
env_init,        // 初始化环境变量存储
init_baudrate,   // 初始化控制台波特率
serial_init,     // 初始化串口
console_init_f,  // 初始化控制台(第一阶段)
display_banner,  // 打印U-Boot启动信息
print_cpuinfo,   // 打印CPU信息
checkboard,      // 打印开发板信息
dram_init,       // 计算并保存SDRAM配置信息
NULL,
};

每个函数指针非NULL的函数都会被依次执行,如果任何函数执行失败,系统将挂起。

3.2 外围设备初始化全景

在基础初始化之后,U-Boot开始初始化更复杂的外设,为加载内核和用户交互做准备:

  1. Flash初始化flash_init() - 识别并初始化Nor Flash,建立Flash分区信息。
  2. 内存分配器初始化mem_malloc_init() - 初始化堆管理器,为后续的动态内存申请(如malloc)做准备。
  3. NAND Flash初始化nand_init() - 如果系统支持NAND,则初始化NAND控制器和驱动。
  4. 环境变量重定位env_relocate() - 将环境变量从Flash(如Nor的特定扇区或NAND的OOB区)加载到RAM中。
  5. 外围设备初始化devices_init() - 初始化其他平台设备。
  6. 中断使能enable_interrupts() - 此时才使能系统中断。
  7. 网络初始化:如 cs8900_get_enetaddr() - 初始化网卡,获取MAC地址,为网络下载功能做准备。
  8. 总线初始化i2c_init() - 初始化I2C总线,用于访问EEPROM、PMIC等I2C设备。
  9. 显示设备初始化drv_lcd_init() - 初始化LCD控制器和背光,为图形化启动界面或LOGO显示做准备。
3.3 终极舞台:主循环

当所有初始化工作完成后,U-Boot最终进入它的“舞台中心”——main_loop() 函数。

for (;;) {
main_loop(); // 位于 common/main.c
}

main_loop() 中,U-Boot会:

  • 执行启动延时倒计时。
  • 处理用户输入(在倒计时内按下任意键进入命令行模式)。
  • 根据环境变量(如 bootcmd)自动启动内核(启动加载模式)。
  • 如果进入命令行模式,则解析并执行用户输入的各种命令(下载模式)。

总结

U-Boot的启动过程是一个从底层硬件到上层应用的完美递进:

  • Stage1(汇编阶段):在“黑暗”中摸索,从设定异常向量开始,逐步构建光明(初始化SDRAM),最终搭建起C语言的舞台(设置栈、清零BSS段)。它的每一步都至关重要,任何错误都会导致系统“猝死”。
  • Stage2(C语言阶段):在Stage1搭建的舞台上,各种“角色”依次登场(CPU、串口、内存、Flash、网卡等),按照严格的顺序完成初始化。最终,舞台准备就绪,U-Boot作为“主持人”登场,要么按照剧本(bootcmd)自动执行,要么等待观众(用户)的指令。

理解这个过程,就如同掌握了嵌入式系统从“沉睡”到“苏醒”的全景图,无论是进行系统移植、性能优化还是疑难排查,都将得心应手。

http://www.rkmt.cn/news/21080.html

相关文章:

  • 两数相加-leetcode
  • 线程共享区域
  • 运行时数据区
  • AI4S Cup学习赛 - 超导体临界温度预测
  • Linux之线程池 - 指南
  • 5G x 工业应用:探索德承工控机在5G工业应用中所扮演的关键角色 - 实践
  • 背叛 仇恨 消极 如刀子刺穿了铁心 嘲笑 嗤之以鼻 漠然后只剩下孤寂
  • 【论文复现上新】AAAI2025!北理工团队提出FBRT-YOLO:面向实时航拍图像更快更好的目标检测 |计算机视觉|目标检测
  • 亚马逊因暗黑模式订阅设计支付25亿美元和解金
  • 2025年排烟风机厂家推荐榜:混流风机|管道风机|排烟风机|离心风机|轴流风机|轴流风机厂家,专注高效消防与节能,助力多行业绿色升级
  • 详细介绍:iCloud照片共享:在家庭内外分享iCloud照片
  • 对static新的认识
  • Excel - lookup()
  • 2025 佛山铝合金/系统/断桥铝/耐用/推拉/封阳台/别墅/静音门窗厂家品牌实力推荐:聚焦技术与服务的五大优选标杆
  • 说说新版畅联云的一些重要约定
  • App.vue(完整可运行示例)
  • Avalonia Behaviors 在 StackPanel 空白处无效问题解析与解决方案
  • 完整教程:Django 入门:快速构建 Python Web 应用的强大框架
  • 高级语言程序第一次作业
  • Windows MySQL 管理
  • 数据流通合规新基建 隐私计算平台的三重安全防线
  • 小程序分享
  • 图论 Walks Trails and Paths in Graph Theory 路径,链,简单路径
  • 2025 年国内面板生产厂家最新推荐排行榜,涵盖耐用 / 肤感 / 半透 / 防指纹 / 电镀 / 防静电面板等多特性优质面板厂家推荐
  • 淘宝店铺全量商品接口深度开发:从分页优化到数据完整性保障 - 实践
  • 敏捷研发管理工具深度测评:ONES、Jira、YouTrack 等 10 款全维度分析
  • 护理白板系统统一外网映射配置
  • openldap之slappasswd
  • 【STM32 系列】理清 xxRAM、xxROM、xxFlash 的核心作用,附 H7 系列超便捷内存区域管理方法
  • 今天被公司告知不续签合同了,我被优化了 哈哈哈