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

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

3天内不再提示

解析U-Boot板级核心代码board.c:从硬件初始化到内核启动的关键一步

jf_44130326 来源:Linux1024 2026-02-03 15:25 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

嵌入式开发中,U-Boot作为最常用的启动加载程序(Bootloader),承担着"承上启下"的关键角色:它负责初始化硬件、设置启动环境,最终引导操作系统内核启动。而board.c作为板级定制的核心文件,是针对具体硬件平台的"个性化配置中心"。今天我们就通过一份实际的board.c代码,聊聊它的核心功能、开发者关注的重点,以及这些代码在U-Boot阶段的关键意义。

一、board.c:板级硬件的"初始化总控"

wKgZPGkam2yAc_9qAACx-Zni_b4155.png

board.cU-Boot中与具体硬件平台强相关的代码文件,几乎所有针对特定板卡的初始化逻辑、硬件配置、启动流程定制都会集中在这里。无论是芯片型号识别、内存大小检测,还是GPIO/ADC等外设的初始化,最终都会通过board.c中的函数落地。

从提供的代码来看,这份board.c主要面向Rockchip RK3588芯片的板卡,包含了硬件识别、环境变量设置、启动流程控制等核心功能。我们可以将其核心函数分为几大模块:

模块1:硬件信息识别与环境变量设置

U-Boot需要通过环境变量(如socdram_size)向下游(如内核)传递硬件信息,这些信息通常由board.c中的函数采集并设置。(这部分是我自己添加的功能,存在环境变量中,供大家参考)

SBCID():通过ADC识别硬件版本

这是开发者新增的自定义函数,作用是通过ADC模数转换器)检测特定通道的电压,映射到8个等级并存储到环境变量SBCID中。

原理:不同硬件版本的板卡可能在ADC引脚接有不同电阻,导致电压不同,通过电压范围匹配即可区分硬件版本。这在多版本板卡的批量生产中非常实用,可自动适配不同硬件配置。

chips_display():标识芯片型号

直接将环境变量soc设置为"rockchip RK3588",明确告知下游当前使用的芯片型号,方便内核或应用针对性适配。

dram_sizes():计算并设置内存大小

从全局变量gd->ddr_sizesU-Boot的全局数据结构,存储DDR信息)中读取内存总大小,转换为"GiB"单位并设置到dram_size环境变量。内核启动时可通过该变量了解内存配置。

JusticeID():通过GPIO组合识别硬件ID

另一处自定义逻辑:读取GPIO139140141的输入电平,组合为3位二进制数(0-7),再映射到特定字符串(如"6""3"等),存储到JusticeID环境变量。

用途:比ADC识别更直接的硬件区分方式,通过GPIO电平组合可快速定位板卡的具体型号或配置(如是否带外设、接口类型等)。

模块2:板级初始化入口函数

U-Boot的初始化流程分为多个阶段,board.c中的初始化函数会在特定阶段被调用,完成硬件准备。

rk_board_late_init():板级后期初始化

作为弱函数(__weak),它是板级初始化的"汇总点",调用了前面提到的SBCID()chips_display()等函数,还输出U-Boot版本。开发者可通过重写该函数,添加自定义的后期初始化逻辑(如外设使能、状态检测)。

board_init():板级早期初始化

负责调试初始化(board_debug_init())、时钟探测(clks_probe())、regulators使能(电源管理芯片初始化)等关键操作。这是硬件"上电后第一步"的初始化,确保核心外设(如UARTDDR)处于可用状态。

board_late_init():系统级后期初始化

rk_board_late_init()更靠后,负责网络地址(rockchip_set_ethaddr())、序列号(rockchip_set_serialno())设置,以及USB启动检测(boot_from_udisk())、充电显示(charge_display())等。此时硬件已基本就绪,开始为启动内核做准备。

模块3:启动流程控制与内核引导

U-Boot的最终目标是引导内核启动,board.c中包含大量与启动流程相关的逻辑。

boot_from_udisk():从U盘启动的适配

检测USB存储设备,若存在有效镜像则设置启动设备为USB,并调整设备树(FDT)地址,确保内核能从U盘加载。这在系统升级、救砖场景中非常实用。

env_fixup():环境变量内存地址调整

根据内存大小(如128M/256M)和是否启用OP-TEE(安全执行环境),动态调整kernel_addr_rramdisk_addr_r等环境变量的地址,避免内存重叠(如内核与ramdisk地址冲突)。

cmdline_handle():启动参数(cmdline)处理

根据启动设备(如SD卡、U盘)和启动模式(如恢复模式),动态更新bootargs(内核启动参数)。例如,从U盘恢复时添加usbfwupdate标识,告知内核进入升级模式。

board_fdt_fixup():设备树(FDT)修复

设备树是内核与硬件沟通的"桥梁",该函数负责在启动前修复设备树(如CPU兼容性检查、显示配置修正),确保内核拿到的设备树与实际硬件匹配。

模块4:其他辅助功能

rockchip_set_ethaddr()rockchip_set_serialno():生成并设置以太网MAC地址和设备序列号,确保网络唯一性和设备可标识性。若硬件中未预存(如烧录到OTP/EFUSE),则自动生成随机值并存储。

board_rng_seed():为内核提供随机数种子,用于Linux内核的随机数初始化(尤其Android 14+ GKI要求必须提供),增强系统安全性。

autoboot_command_fail_handle():自动启动失败时的处理逻辑,例如启动失败后进入Fastboot模式,方便开发者调试或重刷系统。

二、开发者为什么关注board.c

对于嵌入式开发者来说,board.c是硬件与软件的"连接点",其重要性体现在三个方面:

1.硬件初始化的"最后一公里",获取基本信息

芯片手册中定义的外设(如GPIOADC)需要通过board.c中的代码实际使能和配置。例如,若ADC通道未正确初始化,SBCID()就无法读取电压;若GPIO未设置为输入模式,JusticeID()就无法获取正确电平。

2.启动流程的"定制化入口"

不同产品的启动需求不同:有的需要优先从U盘启动,有的需要根据硬件版本加载不同设备树,这些都需要在board.c中通过函数(如boot_from_udisk()env_fixup())定制。

3.问题排查的"关键线索"

若内核启动失败(如内存识别错误、外设不可用),很大概率是board.c中的初始化逻辑有问题。例如,dram_sizes()计算错误会导致内核看到的内存大小与实际不符,进而引发崩溃。

三、这些代码在U-Boot阶段的意义

U-Boot的核心使命是"为内核启动铺路",而board.c中的代码正是完成这一使命的核心工具:

硬件就绪:通过board_init()等函数初始化CPUDDR、时钟、电源等核心硬件,确保内核启动时所有外设处于可用状态。

环境统一:通过环境变量(如socdram_size)向内核传递硬件信息,避免内核重复检测硬件,提高启动效率。

流程可控:通过boot_from_udisk()cmdline_handle()等函数,支持灵活的启动策略(如多设备启动、恢复模式),提升产品的易用性和可维护性。

四、自定义代码的参考价值

文中的SBCID()JusticeID()是开发者新增的逻辑,这类代码的参考意义在于:

硬件差异化处理:在多版本板卡(如同一型号的不同配置)中,通过ADCGPIO快速区分硬件,自动适配驱动或配置,减少代码冗余。

低成本识别方案:无需额外的存储芯片(如EEPROM),利用现有ADC/GPIO实现硬件识别,降低硬件成本。

可扩展性示范:展示了如何在U-Boot中添加自定义逻辑并通过环境变量向下传递,为其他定制需求(如外设检测、状态上报)提供参考。

总结

board.c作为U-Boot的板级核心文件,是硬件初始化的"总导演"、启动流程的"控制器"、硬件信息的"传递者"。理解其函数逻辑,不仅能帮助开发者快速定位启动问题,更能根据产品需求定制灵活的启动策略。而其中的自定义代码(如硬件识别逻辑),则展示了嵌入式开发中"用软件适配硬件差异"的实用思路,值得大家参考借鉴。

下一次调试U-Boot启动问题时,不妨从board.c入手——这里大概率藏着解决问题的关键!



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

    关注

    5209

    文章

    20629

    浏览量

    336790
  • 内核
    +关注

    关注

    4

    文章

    1474

    浏览量

    43089
  • u-boot
    +关注

    关注

    0

    文章

    135

    浏览量

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

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    U-Boot在AT91RM9200上的移植及启动分析

    移植之前,先来了解U-Boot启动过程。U-Boot启动过程可以分成3个阶段。(1)在FLASH中运行汇编程序,进行基本
    发表于 03-16 11:00

    基于开发U-Boot移植

    经有了CPU相关代码。2.下一步就是查看板相关代码了。款主流CPU发布的时候,厂商
    发表于 01-14 14:31

    开发上移植U-Boot

    经有了CPU相关代码。2.下一步就是查看板相关代码了。款主流CPU发布的时候,厂商
    发表于 01-14 14:36

    【OK210试用体验】u-boot篇 -- u-boot一步定制

    【OK210试用体验】u-boot篇 -- u-boot一步定制 u-boot单板的自定义,
    发表于 09-07 11:38

    【OK210试用体验】u-boot篇 -- u-boot启动流程总结

    S5PV210上电后,先运行iROM里的 BL0 段代码,执行完对CPU的系列初始化后,会SD/MMC/NorFlash/NandFLash...里拷贝扇区1的
    发表于 09-08 22:45

    U-BOOT启动流程分享

    语言不能直接访问,C运行之前需要准备堆栈),C阶段两次搬移:u-boot自搬移,内核搬移两次初始化:基本
    发表于 01-18 10:17

    u-boot简介

    点。 U-Boot是BootLoader的种,是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软
    发表于 10-14 11:17 3997次阅读

    U-Boot启动内核的工作过程详细说明

    U-Boot 启动内核的过程可以分为两个阶段,两个阶段的功能如下:(1)第阶段的功能 硬件设备初始化
    发表于 12-28 08:00 3次下载
    <b class='flag-5'>U-Boot</b><b class='flag-5'>启动</b><b class='flag-5'>内核</b>的工作过程详细说明

    u-boot在汇编启动阶段的相关操作介绍

    相关操作 _start开始,u-boot会根据board定义做些平台相关的初始化工作或者是
    的头像 发表于 12-07 11:22 1885次阅读

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

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

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

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

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

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

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

     U-Boot 代码初始加载地址(通常是片内 ROM 或 Flash)复制运行效率更高的片外 RAM,再切换执行环境
    的头像 发表于 11-28 07:05 958次阅读
    深入理解 RK3506 <b class='flag-5'>U-Boot</b> 重定位:<b class='flag-5'>从</b><b class='flag-5'>代码</b><b class='flag-5'>到</b>原理

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

    作为Android设备启动的第道“闸门”,Bootloader(以U-Boot为主)承担着初始化硬件、加载
    的头像 发表于 01-22 07:06 469次阅读
    深入<b class='flag-5'>解析</b>rk平台Android Bootloader<b class='flag-5'>核心</b><b class='flag-5'>代码</b>:<b class='flag-5'>从</b><b class='flag-5'>启动</b>流程<b class='flag-5'>到</b>AVB验证

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

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