ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

飞腾D2000平台U-Boot移植实战:从编译到启动的完整指南

飞腾D2000平台U-Boot移植实战:从编译到启动的完整指南 最近在折腾飞腾D2000平台的Uboot移植从拿到开发板到系统能正常启动前后差不多花了两周时间。这个项目难度不算高但中间细节特别容易踩坑——交叉编译工具链版本不对、设备树配置错误、DDR参数没调好任何一个环节出错都会让你对着串口的一片空白发呆。这篇文章就是这次飞腾D2000平台Uboot移植实战的完整记录从源码编译、板级适配到烧录启动把关键步骤和踩过的坑都梳理出来给准备在这类国产平台上做引导层适配的兄弟做个参考。飞腾D2000现在用得越来越多信创项目、办公终端、边缘服务器都能看到它的身影。它是飞腾面向桌面和服务器市场推出的处理器8核FTC663架构兼容ARMv8指令集算力在国产芯片里属于主流水准。但很多团队拿到板子第一步就卡住了——官方的BSP偏重UEFI方案Uboot的资料相对零散社区里能搜到的完整流程不多。实际上在飞腾D2000上移植Uboot和在其他ARM SoC上做移植的套路是相通的只要把平台差异点搞清楚过程完全可控。1. 移植前必须搞清楚的基础问题1.1 飞腾D2000平台到底特殊在哪先说硬件背景。飞腾D2000虽然兼容ARMv8指令集但它不是ARM公版IP的简单套壳CPU核心是飞腾自研的FTC663内部互联、中断控制器、时钟树都有自己的一套设计。这意味着你不能完全照搬其他ARM平台的做法比如树莓派或者RK3568的Uboot配置拿来直接编译肯定跑不起来。从启动架构上看飞腾D2000的启动链路是这样的芯片上电后固化在片内ROM里的BootROM代码先执行BootROM会去初始化存储控制器然后从SPI Flash或者SD卡等启动介质里加载Bootloader到片内SRAM或者DDR里执行最后由Bootloader去引导操作系统内核。整个过程和大多数ARM平台的启动流程没有本质区别Bootloader层就是我们要动手的Uboot。和普通ARM开发板相比飞腾D2000移植Uboot时有几个明显差异点需要注意。第一BootROM对Bootloader的格式有要求飞腾平台通常使用经过打包的镜像格式而不是裸的u-boot.bin这一点在烧录时必须搞清楚。第二D2000的DDR控制器是自研IP初始化逻辑和常规ARM平台完全不同Uboot源码里必须包含对应的DDR初始化代码这部分也是最容易出问题的。第三飞腾的板级硬件设计各家厂商差异比较大同一颗芯片不同开发板的串口引脚、网卡PHY地址、时钟源配置都可能不同所以设备树的适配工作量是没法省的。1.2 为什么选择Uboot而不是UEFI飞腾官方主推的是UEFI固件方案那为什么还要费劲移植Uboot这是很多刚接触飞腾平台的人会问的问题。从我实际项目经验来看选择Uboot主要有几个现实考量。一个很直接的原因是定制灵活性。UEFI固件虽然功能完整、对标准操作系统兼容性好但它的开发门槛高里面很多模块是二进制闭源的出了问题想调试非常痛苦。Uboot是开源项目从源码到编译工具链全部开放遇到问题可以自己加打印、加调试逻辑对于需要深度定制引导流程的嵌入式场景来说这种可控性太重要了。另外在资源受限或需要快速启动的场景下Uboot也有优势。UEFI的启动链路长、初始化代码多整体启动时间相对较慢。Uboot精简以后可以做到秒级启动对于工控、电力、交通这类对启动时间有要求的行业Uboot是更合适的选择。当然不是说UEFI不好。如果你的项目需要标准化程度高、支持安全启动和大量外设协议栈那么直接使用飞腾官方的UEFI固件会更省事。但如果你的目标是做深度定制、快速适配或者学习研究Bootloader的工作原理Uboot绝对值得投入精力。2. 环境准备与源码编译2.1 交叉编译工具链搭建Uboot是运行在目标板上的程序我们的开发机通常是x86架构的电脑所以需要用到交叉编译工具链让x86机器编译出ARM架构能执行的机器码。飞腾D2000是ARMv8架构64位因此需要aarch64版本的交叉编译器。工具链的版本选择有个讲究。飞腾官方SDK推荐的编译器版本偏保守通常基于GCC 7.3或者GCC 9.x定制。不建议直接用最新版的GCC比如GCC 12、GCC 13因为新版编译器对代码的优化策略、警告处理方式都有变化有可能导致老旧的Uboot源码编译报错或者编译出来的二进制运行时行为异常。我最初图省事用了Ubuntu 22.04自带的aarch64-linux-gnu-gccGCC 11编译过程中就遇到了几个莫名其妙的警告和错误后来换回GCC 9.3问题就消失了。工具链安装比较容易在Ubuntu系统上直接执行sudo apt install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu安装完成后确认一下版本aarch64-linux-gnu-gcc -v如果输出中显示gcc version 9.x或者7.x那就没问题。如果不巧装了新版本可以手动下载Linaro提供的aarch64工具链解压后把bin目录加到PATH环境变量里即可。我个人更推荐用Linaro工具链因为它的版本归档完整项目开发中需要复现环境时很方便。2.2 Uboot源码获取与配置飞腾D2000的Uboot适配代码官方在开源社区有维护不过它并不在主线U-Boot里需要从飞腾的开源仓库拉取。仓库地址一般以phytium或飞腾开发者社区的关键字搜索就能找到代码托管在Gitee平台上这一点比较友好国内拉取速度很快。源码拉取git clone https://gitee.com/phytium_embedded/phytium-uboot.git cd phytium-uboot git branch -a拉下来后先看分支列表通常会有针对不同芯片型号的适配分支选择对应d2000的分支即可。这里有个小建议不要直接拉最新主分支而是查看一下项目的release标签选择经过验证的稳定版本。我这次用的版本是phytium-uboot的某个release分支基于主线U-Boot 2021.04版本定制整体稳定性不错。源码拿到后先确认有没有针对D2000的defconfig配置文件ls configs/ | grep -i phytium ls configs/ | grep -i d2000正常情况下会看到类似phytium_d2000_defconfig这样的文件。如果没有就得从相近的配置改起工作量会大不少。好在飞腾官方的仓库里配置是齐全的。2.3 编译执行与产物说明配置和编译Uboot遵循标准的U-Boot编译流程但有几个关键参数必须注意。第一步设置环境变量指定交叉编译器前缀。这里必须用64位的编译器前缀aarch64-linux-gnu-而不是32位的arm-linux-gnueabihf-很多新手就在这里栽跟头编译出来的镜像在D2000上跑不起来因为CPU核心架构是AArch64模式。第二步执行配置和编译export ARCHarm64 export CROSS_COMPILEaarch64-linux-gnu- make phytium_d2000_defconfig make -j$(nproc)编译过程如果顺利几分钟就能完成取决于机器性能。编译结束后在源码根目录下会生成几个关键文件u-boot.binUboot的原始二进制镜像u-boot.elf带调试信息的ELF格式镜像适合JTAG调试u-boot.map符号映射表排查问题时非常有用的文件u-boot.dtb编译过程中生成的设备树二进制文件这里要注意飞腾平台烧录通常不能直接用裸的u-boot.bin有些板子需要把Uboot打包成固件工具能识别的格式这一步在编译选项里需要确认是否生成了类似fip.bin或者u-boot.flash.bin的产物。如果没有就得根据开发板的手册单独打包。这个点我在第4节烧录部分会详细说。3. 板级适配让Uboot在你的板子上跑起来3.1 设备树硬件拓扑的说明书编译完的Uboot只是个通用框架要让它在具体的板子上跑起来必须告诉Uboot这块板子的硬件是怎么组织的——内存多大、串口在哪个地址、网卡用什么PHY、GPIO怎么复用这些信息都放在设备树Device Tree里。飞腾D2000的设备树源文件在arch/arm/dts/目录下通常以phytium-d2000.dtsi和对应的板级dts文件形式存在。.dtsi文件描述的是D2000这颗芯片内部所有IP的信息比如UART、GMAC、I2C、PCIe控制器的寄存器地址和中断号这部分一般不用动。板级dts文件描述的是具体开发板的硬件配置比如内存大小、外设连接情况这部分是适配的重点。我这次适配主要改了三个地方。第一是内存配置memory节点的reg属性要改成实际板载内存的大小和起始地址飞腾D2000的内存起始地址一般是0x80000000如果板子有8GB内存reg属性就要写成0x0 0x80000000 0x0 0x20000000——但实际中D2000平台内存映射要参考具体参考设计不能想当然填。第二是串口配置确认串口引脚复用是否和开发板的设计一致如果串口不通Uboot启动时的任何输出都看不到排查问题会非常被动。第三是网卡PHY的地址和复位逻辑D2000内置MAC但外部PHY芯片的型号和地址因板而异这部分配置错了Uboot阶段ping不通、内核阶段网卡起不来都是常见病。设备树语法的编写本身不难难的是对硬件设计的理解。我建议动手改dts之前先把开发板的原理图仔细看一遍特别是电源、时钟、复位、启动配置这几类引脚很多启动问题追溯到最后都是某个引脚配置和硬件设计不一致导致的。3.2 内存与时钟最容易出问题的部分在Uboot移植中内存初始化不成功是启动失败的绝对大头。飞腾D2000的内存控制器是自研IPDDR初始化时序、训练算法都由专用代码完成在Uboot源码里通常对应一个独立的目录比如drivers/ram/phytium/。具体需要关注的是DDR频率和时序参数。D2000最高支持DDR4-3200但板子的实际布线质量、走线长度、拓扑结构都会影响最高稳定频率。我这次用的开发板标称支持DDR4-2666我在Uboot配置文件里先把内存频率设定为保守的2400MHz确保系统能稳定启动后续再逐步提高频率验证。千万不要一上来就按最高频率配置DDR训练失败时启动过程会直接死掉而且没有任何输出排查起来极其痛苦。时钟配置同样要谨慎。飞腾D2000内部有复杂的时钟树CPU频率、总线频率、外设频率都是可配的。Uboot源码里一般有默认的时钟配置如果没有特殊需求保持默认即可。如果要超频或者降频一定要确认散热方案和电源供电能力否则CPU不稳定会导致随机死机这种问题最难复现也最难查。3.3 外设初始化与裁剪Uboot阶段的外设不用做得很全通常只需要保证启动需要的最小集串口用于输出日志网卡用于网络启动和调试存储控制器SATA/SD/eMMC用于读取内核镜像其他外设可以全部裁剪掉。这样既可以减小Uboot镜像体积也能降低启动阶段出问题的概率。裁剪的方法很直观修改defconfig文件中的配置项不需要的功能直接取消。比如不需要I2C工具就把CONFIG_CMD_I2C关掉不需要USB Host功能就把CONFIG_USB相关的选项关掉。裁剪的时候注意一点有些功能看似无关实际上是Uboot内部其他模块的依赖关掉会导致编译错误。遇到这种依赖问题编译错误信息里会提示是哪个配置项被依赖顺着提示去打开对应的配置项或者查找Kconfig文件里的依赖关系基本都能解决。我这次裁剪后的Uboot镜像从默认的接近1MB缩小到不到500KB启动速度也有明显提升。对于有启动时间要求的项目裁剪是很有价值的优化手段。4. 烧录固化与系统启动4.1 固件烧录的几种方式Uboot编译好之后要把它烧到板子的启动介质里。飞腾D2000开发板通常支持SPI NOR Flash和SD卡两种启动方式不同板子的具体操作路径略有差异但总体思路是一致的。用SD卡启动是最方便的调试方式。把编译好的Uboot镜像放到SD卡指定位置设置板子的启动拨码开关为SD卡启动模式上电后BootROM会自动从SD卡加载Uboot执行。这种方式适合开发阶段反复修改测试不用频繁擦写Flash风险也低。具体SD卡的分区格式和镜像放置位置开发板的手册里会有说明一般是把裸的Uboot镜像写入SD卡的偏移地址处可以用dd命令操作。SPI NOR Flash烧录是正式固化时的方式。飞腾平台一般会提供专门的烧录工具通过串口或者USB和板子通信把Uboot镜像写入Flash。烧录时注意Flash的型号和大小飞腾参考设计上SPI Flash通常是32MB或者64MBUboot镜像放在最开始的区域后面通常是UEFI或者其他固件的空间。烧录前一定要先擦除再写入别直接叠加写否则Flash里的数据会错乱。实际开发中还可能遇到JTAG烧录的方式适合板子BootROM都坏了、完全是砖的状态。JTAG方式需要仿真器比如J-Link的A64版本或者DAPLink调试起来非常强大可以单步执行Uboot代码对排查启动早期的问题特别有帮助。不过JTAG烧录需要连接硬件调试接口不是每块板子都引出了这些引脚这个要看具体情况。4.2 启动流程与日志解读烧录完成后上电调试通常通过串口工具连接板子的调试串口波特率常见的是115200或者1500000D2000平台有些默认是1500000。连接好串口后给板子上电会在串口终端看到类似下面的输出U-Boot 2021.04-phytium (Feb 20 2025 - 10:30:00 0800) CPU: Phytium D2000 DRAM: 8 GiB这几行输出代表BootROM已经把控制权交给了UbootUboot完成了最基础的CPU、内存初始化。看到DRAM容量正确识别说明内存配置没有问题这是移植过程中最关键的一个里程碑。之后的日志会显示Uboot对外设的枚举过程包括MIPI、PCIe、网卡控制器等初始化。如果设备树配置有问题某些外设会初始化失败日志里会有对应的错误提示。拿到日志后要养成确认三个关键点的习惯。第一看CPU型号是否正确确认Uboot认到的是D2000而不是其他芯片。第二看DRAM容量是否与实际内存一致不一致说明内存配置有问题系统运行时会出现不明原因的随机重启。第三看启动介质是否正确识别特别是后续还要从Flash或者SD卡加载内核镜像的情况。这三个点确认无误基本可以断定Uboot层是稳了后面的事就好办多了。4.3 与内核启动的衔接Uboot跑起来只是第一步最终系统启动还需要Uboot加载内核镜像然后跳转到内核执行。Uboot要从某处获取内核常见的有几种方式从SD卡或Flash读取内核镜像、通过网络TFTP下载内核镜像、通过USB下载较少见但支持。调试阶段最推荐TFTP方式。在开发机上搭建TFTP服务器把内核镜像和设备树文件放到TFTP目录里Uboot里设置好网络参数后用tftp命令加载内核到内存然后用bootm命令启动整个过程循环很快不用反复烧写Flash。实际对应的Uboot命令流程类似setenv serverip 192.168.1.100 setenv ipaddr 192.168.1.150 tftp 0x90000000 Image tftp 0x92000000 phytium-d2000.dtb bootm 0x90000000 - 0x92000000命令成功后会看到内核开始启动的日志输出说明Uboot到内核的引导链路已经完全打通。到这一步Uboot移植工作算是圆满完成剩下的内核对设备的适配就是另一个话题了。5. 常见问题与排障实录5.1 编译阶段的典型问题移植Uboot过程中编译错误是最容易遇到也最好解决的问题。这里把常见的编译问题和排查思路整理成表格方便快速定位。问题现象可能原因排查与解决方法编译报错unknown type name或implicit declaration交叉编译器版本过高代码不兼容新GCC换用GCC 7.x或9.x版本工具链编译报缺少openssl/xxd等依赖主机缺少必要工具安装对应依赖如sudo apt install xxd libssl-dev uuid-devPython脚本相关报错主机Python版本不兼容检查并安装Python 3部分旧脚本需Python 2环境链接时报aarch64-linux-gnu-ld: cannot find crt0.o工具链安装不完整重新安装交叉编译工具链完整版配置时报无法找到defconfig拉取的仓库分支不对或路径错误检查源码分支确认在根目录执行make命令我这里想多说一句编译器版本问题。很多刚接触嵌入式开发的兄弟习惯用最新的开发环境觉得版本越新越好。但在Uboot移植这种对兼容性要求极高的场景里老牌编译器的稳定输出比新编译器的花哨优化有价值得多。飞腾官方SDK里打包的工具链不一定是版本最新的一定是经过充分测试的直接用官方推荐版本能省太多无谓的时间。5.2 启动阶段的高频问题启动阶段的问题比编译阶段麻烦得多因为表现千奇百怪而且很多情况下没有直接报错信息只能靠经验和排查一步步缩小范围。最让人头疼的情况是串口完全没有输出。遇到这种情况先不要急着怀疑Uboot代码按优先级排查第一确认串口连接和波特率设置是否正确D2000平台有些开发板的调试串口默认波特率是1500000而不是115200这个坑我之前帮同事排过他拿着115200波特率连着板子看了一晚上黑屏换波特率之后日志刷得飞快。第二确认板子的启动拨码开关是否拨到了正确的介质如果板子配置从SPI Flash启动而你烧录了SD卡那自然是黑屏。第三才是怀疑代码问题通过JTAG挂仿真器看BootROM是否执行、能否跳到Uboot。还有一种常见情况是启动打印了一部分日志但卡在DRAM初始化或者某个驱动初始化位置。这种通常和特定外设有关。卡在DRAM初始化就要检查DDR频率和参数设置尝试降低频率。卡在某个USB设备或者PCIe设备枚举上可以先在defconfig里禁用该功能排除干扰后再逐个恢复。内存报错也是一个高频问题常见现象是Uboot识别到的内存容量比实际小或者启动过程中随机死机。识别容量不对大概率是设备树里的reg属性配置不对随机死机则要怀疑DDR时序参数太激进或者供电不稳定先降频跑一段稳定性测试再说。5.3 几个实用的避坑技巧最后分享几个我在调试过程中总结出来的小技巧虽然不值钱但关键时候能救命。一个技巧是善用串口工具的日志记录功能。从给板子上电的那一刻起就把所有串口输出完整记录保存下来。有时候问题不是立刻出现的可能连续启动五次第五次才失败如果前面的日志都没保存就很难发现问题的规律。我习惯把每次启动日志按照时间戳命名归档出问题时回溯对比往往能发现重要线索。另一个技巧是尽量保持改动最小化一次只改一个东西。移植过程中总是会有很多想优化的冲动比如内存频率、网络性能、启动速度全都想调到最佳。但排查问题最忌讳的就是多变量同时变化改完出问题根本定位不了根因。保守做法是先用默认配置调通整个启动流程然后每改一个配置就完整跑一次启动测试确认稳定后再进行下一项看起来慢实际是最快的方式。还有一个小技巧是善用make menuconfig查看配置依赖。虽然defconfig可以直接改文本但有时候一个选项被另一个选项依赖改半天编译不过去。menuconfig可以直观地看到当前配置项的状态和依赖关系避免盲目修改。我在实际调试中还发现飞腾平台的Uboot对网络启动特别依赖PHY芯片的稳定性和复位时序如果网卡在Uboot阶段时通时不通优先检查PHY复位引脚的GPIO配置和延迟时间很多网卡问题不是驱动逻辑的问题而是硬件初始化时序没满足PHY芯片的要求。这类问题用示波器抓一下波形就能定位但很多做软件的兄弟手边没这工具那就只能靠软件层面反复调整复位延迟来试了。这次飞腾D2000平台Uboot移植的过程前前后后也踩了不少坑但真把整个流程跑通之后再回头看其实整体思路和普通ARM平台没有太大区别无非是平台特色的硬件细节需要花时间熟悉。移植工作最磨人的不是代码本身而是调试过程中那种面对未知的耐心。每一步小进展都值得记录每个报错信息都别跳过保持这样一点点推进最终系统启动日志刷出来的那一刻还是很有成就感的。
返回列表