首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
openEuler移植RK3399实战:内核编译与资源镜像制作指南
📅 2026/10/15 17:52:40
✍️ 爱科研究院
👁 阅读 3,247
1. 项目缘起与整体设计思路把 openEuler 20.03 LTS 搬到 RK3399 这块板子上是我去年折腾过最久、也最有意思的一件事。openEuler 本身是面向服务器和云场景的发行版官方支持的架构主要是 x86_64 和 aarch64 的通用服务器平台而 RK3399 是一颗面向嵌入式、边缘计算和开发板的六核 ARM 芯片双核 Cortex-A72 加四核 Cortex-A53。这两者凑到一起本质上是一次“跨场景移植”——把为服务器设计的系统塞进一块功耗低、外设杂、引导链完全不同的板子里。这个系列我打算分几篇写第一篇只解决最基础、也最容易卡住新人的环节内核编译和资源镜像的制作。说白了就是先把一个能启动的底子搭出来。没有这一步后面什么驱动适配、桌面环境、应用部署都是空谈。适合谁来参考我觉得有三类人一是手里有 RK3399 开发板、想跑非官方系统的折腾党二是做边缘设备、想验证 openEuler 在 ARM 嵌入式场景可行性的工程师三是单纯想搞懂 ARM 平台从源码到可启动镜像完整链路的同学。先说清楚整体思路免得一上来就迷路。RK3399 的启动链路和普通 PC 完全不是一回事。PC 上电后走 UEFI/BIOS然后引导 GRUB再加载内核。RK3399 走的是 Rockchip 自己的一套流程芯片内部固化的 BootROM 先跑加载外部存储里的引导固件通常是 U-Boot 的 SPL 和 proper 两段U-Boot 再去加载内核镜像和设备树最后把控制权交给内核。所以我们要准备的东西至少包括交叉编译工具链、内核源码、U-Boot 源码、设备树文件、根文件系统以及把这些东西打包成 Rockchip 能识别的资源镜像的工具。为什么强调“资源镜像”这个词因为在 Rockchip 的语境里最终烧录到板子上的不是一个简单的.img而是由多个分区镜像引导区、内核区、根文件系统区等按特定偏移拼装起来的复合镜像通常用rockchip提供的打包工具生成。这一步如果偏移量搞错板子直接变砖连串口都不一定有输出。我踩过这个坑后面会细说。方案选型上我做了几个关键决定。第一内核版本选择。openEuler 20.03 LTS 默认内核是 4.19 系列这个版本对 RK3399 的支持相对成熟Rockchip 官方也有基于 4.19 的 BSP 分支社区补丁比较全。如果硬上 5.x虽然新特性多但 RK3399 的 GPU、VPU 驱动适配会麻烦很多对新手不友好。第二交叉编译工具链。我选的是 aarch64 的 GNU 工具链而不是用板子本地编译。原因很简单RK3399 性能有限本地编译一个完整内核要一两个小时交叉编译在 x86 主机上十几分钟就搞定效率差一个数量级。第三根文件系统。我一开始想用 openEuler 官方的最小 rootfs但发现它默认针对服务器缺少很多嵌入式需要的基础库和初始化脚本后来改成基于官方 rootfs 做裁剪和补充。提示整个移植过程对主机环境有要求建议用 Ubuntu 20.04 或同级别的 x86_64 主机磁盘至少留 50GB内存 8GB 以上。低于这个配置编译过程会非常痛苦。2. 环境准备与工具链搭建2.1 主机依赖安装与目录规划动手之前先把主机环境收拾干净。我习惯把所有相关文件放在一个统一的工作目录下比如~/rk3399-openeuler里面再分toolchain、kernel、uboot、rootfs、output几个子目录。这样做的好处是路径清晰后面写脚本时引用方便也不容易把不同项目的文件搞混。主机依赖这块主要是编译内核和 U-Boot 需要的库和工具。在 Ubuntu 上一条命令基本能搞定sudo apt update sudo apt install -y build-essential git bc bison flex libssl-dev \ libncurses5-dev libncursesw5-dev device-tree-compiler \ python3 python3-pip rsync cpio kmod u-boot-tools \ gcc-aarch64-linux-gnu g-aarch64-linux-gnu这里有几个包值得单独说。device-tree-compiler提供dtc命令用来编译和反编译设备树RK3399 的外设配置全靠它。u-boot-tools里的mkimage是给内核镜像加 U-Boot 头用的没有它内核加载会失败。bc和bison、flex是内核编译脚本依赖的缺了会在编译中途报错而且报错信息很隐晦新手容易懵。libssl-dev是内核签名模块需要的openEuler 内核默认开启模块签名不装会编译失败。工具链方面我推荐用 Linaro 或者 ARM 官方发布的 aarch64 工具链版本选 7.5 以上。系统自带的gcc-aarch64-linux-gnu也能用但版本可能偏旧编译高版本内核时偶尔会有警告。我实测下来系统自带的工具链编译 4.19 内核没问题追求稳定的话可以直接用。如果要自己下载独立工具链解压后记得把bin目录加到PATH里并且验证一下aarch64-linux-gnu-gcc -v能正常输出版本信息就说明工具链就绪了。2.2 源码获取与版本锁定源码获取这一步坑最多。openEuler 的内核源码在官方仓库里有但它是面向通用 aarch64 的直接拿来编译 RK3399 会缺很多板级支持。我的做法是以 openEuler 20.03 LTS 的内核源码为基线叠加 Rockchip 官方的 BSP 补丁。这样既能保证 openEuler 的软件包兼容性又能拿到 RK3399 的完整驱动。具体操作上先克隆 openEuler 内核源码切换到对应的 4.19 分支然后从 Rockchip 的 BSP 仓库拉取针对 RK3399 的补丁集用git am或者patch打进去。补丁数量不少大概几十个涉及时钟、电源管理、PCIe、USB、显示等模块。打补丁时如果遇到冲突不要慌多半是因为 openEuler 内核和 Rockchip BSP 基线有细微差异手动合并一下即可。我建议打补丁前先git commit一次方便出问题时回滚。U-Boot 源码同理用 Rockchip 的 U-Boot 分支版本选 2017.09 或更新的这个版本对 RK3399 的 SPL 支持比较完善。设备树文件.dts通常在 U-Boot 和内核源码里各有一份U-Boot 用的那份负责引导阶段的硬件初始化内核用的那份负责系统运行时的外设描述两者不能混用。注意源码版本一定要锁定不要用master分支。我吃过亏某次用最新分支编译出来的内核启动到一半卡死排查了两天才发现是某个驱动提交引入了回归。锁定到具体的 tag 或 commit是嵌入式开发的基本纪律。3. 内核编译与设备树配置实操3.1 内核配置裁剪与关键选项内核配置是整个编译过程的核心。RK3399 的默认配置在arch/arm64/configs/下通常叫rockchip_defconfig或者类似的名字。直接用这个配置能启动但体积大、启动慢很多服务器特性根本用不上。我的做法是在默认配置基础上做裁剪同时确保几个关键选项打开。关键选项包括CONFIG_ARCH_ROCKCHIPy芯片平台支持、CONFIG_ARM64_VA_BITS_48y48 位虚拟地址RK3399 支持、CONFIG_ROCKCHIP_IOMMUyIOMMUGPU 和 VPU 需要、CONFIG_SERIAL_8250_DWy串口驱动调试必备、CONFIG_MMC_DW_ROCKCHIPyeMMC 和 SD 卡驱动、CONFIG_USB_DWC3yUSB 3.0 控制器。这些如果漏了板子要么起不来要么起来后外设全废。配置命令用标准的make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- rockchip_defconfig make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- menuconfigmenuconfig里我重点调整了几处关掉CONFIG_DEBUG_INFO调试信息体积巨大移植阶段不需要、关掉CONFIG_MODULE_SIG模块签名嵌入式场景没必要、打开CONFIG_DEVTMPFS和CONFIG_DEVTMPFS_MOUNT让内核自动挂载 devtmpfs省去手动创建设备节点。裁剪完的配置建议保存一份备份比如cp .config ../config-backup下次编译直接复用。3.2 编译过程与产物说明编译命令本身不复杂make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- -j$(nproc) Image dtbs modules-j$(nproc)是并行编译用满 CPU 核心能显著缩短时间。我实测在 8 核主机上完整编译一次大概 12 到 15 分钟。编译产物主要有三个arch/arm64/boot/Image内核镜像未压缩、arch/arm64/boot/dts/rockchip/下的.dtb文件设备树二进制、以及各模块的.ko文件。这里有个细节RK3399 的 U-Boot 通常加载的是Image而不是Image.gz因为 U-Boot 自己可以做解压。但如果你用的 U-Boot 版本较老可能需要Image.gz。我建议两个都生成Image.gz用gzip -k Image即可。设备树文件要选对RK3399 有多个变种比如不同厂商的板子.dtb名字要和你的板子匹配选错了会导致外设识别异常。模块安装到根文件系统时用make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- INSTALL_MOD_PATH../rootfs modules_install这样模块会装到../rootfs/lib/modules/下后面打包根文件系统时一起带上。实操心得编译过程中如果报dtc相关错误多半是设备树语法问题用dtc -I dts -O dtb -o test.dtb your.dts单独编译一下报错信息比内核编译时清晰得多。另外Image生成后建议用file命令确认一下架构输出里应该有ARM aarch64字样避免工具链用错。4. 资源镜像制作与打包流程4.1 分区规划与镜像布局资源镜像的制作是这篇的重头戏。Rockchip 平台的镜像不是单一文件而是按分区表拼装出来的。典型布局包括uboot分区存放 U-Boot 的 SPL 和 proper、trust分区存放 ARM Trusted Firmware负责安全启动和电源管理、boot分区存放内核 Image 和设备树、rootfs分区根文件系统。每个分区在最终镜像里有固定的偏移地址这些偏移由 Rockchip 的打包工具根据配置文件生成。我用的打包工具是 Rockchip 提供的mkfirmware脚本或者afptool它们读取一个parameter.txt文件里面定义了分区名、偏移、大小。这个文件必须和 U-Boot 里的分区表一致否则 U-Boot 找不到内核。parameter.txt的典型内容长这样FIRMWARE_VER: 8.1 MACHINE_MODEL: RK3399 MACHINE_ID: 007 MANUFACTURER: RK3399 MAGIC: 0x5041524B ATAG: 0x00200800 MACHINE: 0xffffffff CHECK_MASK: 0x80 PWR_HLD: 0,0,A,0,1 TYPE: GPT CMDLINE: mtdpartsrk29xxnand:0x000020000x00004000(uboot),0x000020000x00006000(trust),0x000100000x00008000(boot),0x000200000x00018000(rootfs),-0x00038000(userdata)这里每个分区用大小偏移(名字)表示单位是扇区512 字节。uboot从 0x4000 扇区开始大小 0x2000 扇区也就是 4MB。这些数值不是随便写的要和 U-Boot 的配置、内核大小、根文件系统大小匹配。根文件系统如果超过分配的大小打包会失败或者烧录后分区被截断。4.2 打包命令与烧录验证打包流程分几步。先把 U-Boot 编译产物里的idbloader.imgSPL 加 proper 的合并镜像和u-boot.itb准备好trust分区用bl31.elf转换来的trust.imgboot分区用内核Image加.dtb加resource.img资源镜像包含开机 logo 等。resource.img用 Rockchip 的resource_tool生成把图片和 dtb 打包进去。然后执行打包./mkfirmware.sh或者手动用afptool -pack加img_maker组合。生成的最终镜像通常叫update.img可以用 Rockchip 的烧录工具通过 USB 或者 SD 卡写入板子。烧录后第一次启动务必接串口看输出。正常的话能看到 U-Boot 的启动日志、内核解压信息、设备树加载信息最后进入根文件系统的初始化。如果串口没有任何输出先检查idbloader.img是否写到了正确的偏移通常是扇区 64。如果 U-Boot 有输出但内核加载失败检查boot分区的偏移和parameter.txt是否一致。如果内核起来了但根文件系统挂载失败检查rootfs分区格式和内核CMDLINE里的root参数。注意烧录前一定要确认板子的启动模式。RK3399 通常有 eMMC 和 SD 卡两种启动介质通过按键或者跳线选择。烧录到 eMMC 时如果中途断电板子可能变砖需要用 MaskROM 模式救回来。我第一次烧录就是因为没确认启动模式写到了错误的介质上折腾了半天。5. 常见问题与排查技巧实录5.1 编译阶段典型报错编译阶段最常见的问题是工具链找不到、头文件缺失、补丁冲突。工具链找不到通常是PATH没配好或者CROSS_COMPILE前缀写错。头文件缺失多半是主机依赖没装全按前面列的包补装即可。补丁冲突前面说过手动合并合并时注意保留 openEuler 的改动和 Rockchip 的改动不要简单覆盖。还有一个隐蔽的坑内核编译到某个驱动时报undefined reference这往往是因为该驱动依赖的另一个配置项没打开。比如某个网络驱动依赖CONFIG_PHYLIB你没开编译就失败。解决办法是用make menuconfig里的搜索功能按/查依赖关系把依赖项补上。5.2 启动阶段问题速查启动阶段的问题排查我整理了一个速查表按现象对原因现象可能原因排查方法串口无任何输出idbloader 偏移错误或未烧录检查烧录地址是否为扇区 64U-Boot 输出后卡住trust 分区缺失或 bl31 版本不匹配确认 trust.img 已打包且版本对应内核解压后无输出设备树选错或内核配置缺串口驱动换正确 dtb检查 CONFIG_SERIAL_8250_DW根文件系统挂载失败rootfs 分区偏移错误或格式不对核对 parameter.txt 和 CMDLINE 的 root启动后外设不工作设备树节点缺失或驱动未编译用 dtc 反编译 dtb 检查节点这个表是我踩坑踩出来的基本覆盖了 90% 的启动问题。排查时按顺序来从最底层往上查不要跳步。5.3 独家避坑经验最后分享几个文档里不会写的经验。第一串口是你的眼睛移植阶段一定要接串口不要指望 HDMI 输出因为显示驱动可能还没适配好。第二每次只改一个变量比如这次只改内核配置下次只改设备树这样出问题能快速定位。第三保留可启动的旧镜像新镜像烧录前把旧的备份好新镜像起不来可以立刻回退。第四根文件系统先用最小集不要一上来就装桌面环境先把串口和网络跑通再逐步加功能。这个系列后面还会写驱动适配、桌面环境搭建、应用部署等内容。第一篇的目标就是让你手里有一块能启动、能进串口、能挂载根文件系统的板子。做到这一步后面的路就好走多了。我在实际移植中发现最耗时的往往不是技术难点而是环境问题和版本匹配问题把这两块理顺效率能提升一大截。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/15 17:52:40
三菱CNC数据采集Demo用C#实现全流程详解:EZSocket通信与宏变量读取
2026/10/15 17:52:40
CPCL指令详解:快递单打印模板设计与高效打单实战
2026/10/15 17:52:40
广和通FM350GL原厂调试工具深度指南:AT+QENG与NV项诊断实战
2026/10/15 19:03:17
智能体生产落地三大挑战:安全边界、并行搜索与物理执行
2026/10/15 19:03:17
AndroidLibs 按钮 Button 专题:60 个开源按钮组件库的归类速查与选型指南
2026/10/15 19:03:17
避开上海少儿美术培训误区:别只看成品画效果
2026/10/15 19:03:16
智能对话系统架构设计:从模型中心到系统中心的创新思维
2026/10/15 19:03:16
tracing-subscriber 版本演进深度解析:从 0.1 到 0.3 的 Layer 组合、过滤机制与格式化能力全梳理
2026/10/15 18:58:15
HCNetSDK V5.1.1.4 Win64 开发包解析与 C++ Demo 实战指南
2026/10/15 0:02:59
AI Coding时代的柔性之美:从静态软件到自演化软件,软件研发正在重新进化
2026/10/15 0:02:59
亨得利客户服务中心官方网点分布一览:2026年全国多城门店地址与最新联系电话公布
2026/10/15 0:02:59
防关联浏览器哪个好?三款产品实测差异解析
2026/10/13 12:25:09
流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南
2026/10/14 18:35:19
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别
2026/10/14 14:52:59
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容
2026/10/15 1:07:55
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/15 5:07:59
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/15 8:10:01
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)