RK3588移植Ubuntu 26.10实战:从U-Boot到rootfs全链路指南
1. 为什么要在RK3588上折腾Ubuntu 26.10把Ubuntu 26.10跑在RK3588这块板子上听起来像是个吃饱了撑的项目——毕竟RK3588出厂通常配的是Debian或者Ubuntu 22.04的BSP厂商给的镜像开箱即用何必自找麻烦但如果你真的在嵌入式圈子里待过一段时间就会明白这件事的价值远不止尝鲜两个字。先说清楚这个项目的定位RK3588是一颗8核ARM处理器4×Cortex-A76 4×Cortex-A55带Mali-G610 GPU和6TOPS NPU被大量用在边缘计算盒子、工控机、NAS、AI推理设备上。而Ubuntu 26.10代表的是更新的内核、更新的GCC、更新的glibc、更新的Mesa和更完整的Wayland支持。把这两者结合本质上是在解决一个很现实的问题厂商BSP的内核版本往往停留在5.10或6.1用户空间软件包老旧很多新版本的AI框架、图形栈、容器工具链在上面跑起来各种别扭。我自己手上有几块不同厂商的RK3588板子从4GB到16GB内存的都有。过去一年里我反复遇到同一类问题想跑一个新版的推理框架结果glibc版本不够想用最新的Mesa做OpenGL ES 3.2的测试结果驱动版本对不上想用较新的Docker和containerd组合结果内核的cgroup v2支持不完整。每次都要么降级软件要么自己编译一堆依赖非常痛苦。所以当Ubuntu 26.10的镜像和源码树可以获取之后我就决定认真做一次移植。这篇文章适合三类人看第一类是手里有RK3588板子、想跑更新系统的嵌入式开发者第二类是想了解ARM64平台Linux移植完整流程的爱好者第三类是需要在RK3588上部署较新软件栈、被旧BSP折磨过的工程师。我会把整个流程拆开讲包括为什么这么选、每一步在干什么、哪些地方容易翻车以及我实际踩过的坑。需要提前说明的是这不是一篇复制粘贴就能跑的教程。RK3588的板子型号太多电源管理芯片、DDR颗粒、eMMC、网卡、WiFi模组各不相同设备树必须针对你的具体板子调整。我会给出通用的方法和判断依据但具体参数你得自己对着原理图和厂商资料改。2. 移植前的底层认知RK3588的启动链路和Ubuntu的适配边界2.1 RK3588从上电到进系统的完整链路很多人移植失败根本原因是不清楚RK3588的启动流程。这块芯片的启动链路比树莓派那种GPU固件直接加载内核要复杂得多它是典型的多级引导第一级是BootROM固化在芯片内部上电后先跑。它会根据OTP配置和外部引脚状态决定从SPI Flash、eMMC、SD卡还是USB下载模式启动。BootROM会去加载一个叫**TPLTiny Program Loader**的东西通常放在存储介质的特定偏移位置。第二级是TPL SPL。TPL负责初始化最基础的DDR控制器把SPL搬到SRAM里运行SPL再完成更完整的DDR训练和初始化然后加载U-Boot proper。这一步是整个移植里最敏感的环节因为DDR的时序参数、电压配置如果和你的板子不匹配表现就是上电后串口毫无输出或者输出几行乱码就死掉。第三级是U-Boot proper它负责加载设备树、内核镜像和initramfs然后跳转到内核。U-Boot阶段需要正确配置的是启动介质、环境变量、以及传给内核的bootargs。第四级才是Linux内核内核启动后挂载根文件系统最后交给systemd拉起用户空间。理解这条链路的意义在于当你遇到系统起不来的时候必须能判断问题出在哪一级。串口完全无输出大概率是TPL/SPL或DDR的问题有U-Boot输出但卡在加载内核是U-Boot配置或镜像格式的问题内核有输出但卡在挂载根文件系统是bootargs或存储驱动的问题内核完全启动但卡在systemd才是用户空间的问题。这个判断逻辑贯穿整个移植过程。2.2 为什么Ubuntu 26.10的内核不能直接用Ubuntu官方为ARM64服务器提供的内核镜像是为服务器平台比如Ampere、鲲鹏等准备的它不包含RK3588所需的任何设备树和平台驱动。你直接把Ubuntu的generic内核放到RK3588上结果就是内核根本认不出这块SoC连串口都起不来。所以正确的思路是用Ubuntu 26.10的用户空间rootfs搭配一个为RK3588适配过的内核。这个内核可以来自几个渠道Rockchip官方维护的kernel分支、主线Linux内核mainline加上RK3588的设备树、或者社区维护的针对RK3588优化的内核树。我个人的选择是主线内核 Rockchip的补丁集。原因很直接主线内核版本新、代码质量高、后续升级方便但RK3588的某些外设尤其是NPU、VPU硬件编解码、部分显示输出在主线里支持还不完整需要Rockchip的补丁来补齐。Ubuntu 26.10对应的内核版本比较新主线里RK3588的基础支持CPU、DDR、eMMC、SD、串口、以太网、USB已经相当成熟日常使用没问题。2.3 用户空间和内核的版本匹配问题这里有个容易被忽略的细节Ubuntu 26.10的glibc版本较新它要求内核提供较新的系统调用和ABI支持。如果你用一个太老的内核比如5.10去跑Ubuntu 26.10的rootfs某些程序会因为系统调用缺失而崩溃。反过来用太新的内核跑老rootfs通常问题不大因为内核保持向后兼容。实测下来内核版本建议不低于6.6最好是6.12或更新的LTS版本。Ubuntu 26.10的用户空间在这个内核版本上跑起来比较稳。如果你的内核版本偏低可能会遇到systemd报错、某些库加载失败等问题。另外要注意固件文件firmware。RK3588的GPUMali-G610、VPU、NPU都需要对应的固件和用户空间驱动。Ubuntu的linux-firmware包里不一定包含Rockchip的这些固件需要从Rockchip的仓库单独获取并放到/lib/firmware下。这一步漏了表现就是GPU加速用不了、视频硬解不工作。3. 交叉编译环境的搭建与内核配置的取舍3.1 工具链选择为什么不用Ubuntu自带的gcc在x86主机上给ARM64编译你需要一套交叉编译工具链。Ubuntu仓库里有gcc-aarch64-linux-gnu装起来方便但我实测下来更推荐用ARM官方或Linaro维护的预编译工具链原因是Ubuntu自带的版本有时候和内核源码里的某些特性比如特定版本的binutils对某些指令的支持配合不好编译内核时可能报奇怪的错误。我用的是一套基于GCC 13的aarch64工具链。安装方式很简单下载解压后把bin目录加到PATH里就行。验证方法是aarch64-linux-gnu-gcc --version能正确输出版本号就说明工具链可用。这里有个小坑如果你的主机上同时装了多个版本的交叉工具链一定要确认PATH里优先的是你想要的那个否则编译到一半发现用的是系统自带的旧版本会浪费很多时间。3.2 内核配置defconfig只是起点拿到内核源码后第一件事是选一个基础配置。Rockchip的kernel仓库里有rockchip_linux_defconfig主线内核里有defconfigARM64的通用配置。我的做法是以主线的defconfig为基础再用Rockchip的配置片段补充。具体操作是先用make ARCHarm64 defconfig生成基础配置然后通过scripts/config或者直接编辑.config打开RK3588相关的选项。关键选项包括配置项作用是否必须CONFIG_ARCH_ROCKCHIP启用Rockchip平台支持必须CONFIG_ARM64_CRYPTOARM64加密指令加速建议CONFIG_ROCKCHIP_IODOMAINIO域电源管理必须CONFIG_DRM_ROCKCHIP显示子系统需要显示则必须CONFIG_ROCKCHIP_IOMMUIOMMU支持建议CONFIG_PHY_ROCKCHIP_*各类PHY驱动按外设需要CONFIG_MMC_DW_ROCKCHIPeMMC/SD控制器必须CONFIG_STMMAC_ETH千兆以太网按需配置完成后用make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- -j$(nproc)编译。第一次编译建议不要开太多并行任务如果报错日志更容易定位。等确认能编过了再加大并行度。3.3 设备树移植里最需要耐心的地方设备树Device Tree是ARM Linux移植的核心它描述了板子上的硬件怎么连接、地址是多少、用什么驱动。RK3588的SoC级设备树rk3588.dtsi通常由内核或Rockchip提供但板级设备树rk3588-yourboard.dts必须你自己写或改。板级设备树里最关键的几块内存节点要写对DDR的容量和起始地址。RK3588的DDR起始地址通常是0x0容量按你的板子填4GB、8GB、16GB。填错了内核启动时会报内存相关错误。存储节点要指定eMMC和SD卡控制器的状态、总线宽度、时钟频率。如果你的板子eMMC是HS400模式还要配置对应的PHY。串口节点是调试的生命线必须确保调试串口的引脚复用pinctrl配置正确否则你连日志都看不到。电源管理涉及一堆regulator节点描述各个电源域怎么供电。这块最容易出错因为不同板子的PMIC型号和连接方式不同。如果regulator配置错了表现可能是某个外设不工作或者系统运行中随机死机。我的经验是先让最小系统跑起来——只配置CPU、DDR、串口、eMMC/SD确认能进U-Boot、能加载内核、能挂载rootfs。然后再一个一个加外设每加一个测试一次。不要一次性把所有外设都配上出了问题根本不知道是哪个节点的锅。4. 从U-Boot到rootfs让系统真正跑起来的完整链路4.1 U-Boot的编译和烧录位置U-Boot这块Rockchip有自己维护的分支主线U-Boot对RK3588的支持也在逐步完善。我建议优先用Rockchip的U-Boot因为它的DDR初始化和TPL/SPL支持更成熟尤其是DDR训练部分主线版本在某些板子上可能不稳定。编译U-Boot需要指定板子配置比如make rk3588_defconfig然后编译出u-boot.bin、u-boot.itb、idbloader.img等文件。烧录位置非常关键idbloader.img烧到存储介质的0x40扇区偏移32KBu-boot.itb烧到0x4000扇区偏移8MB这两个偏移是RK3588 BootROM约定的写错了BootROM就找不到引导程序。用dd命令烧录时一定要算清楚dd ifidbloader.img of/dev/sdX seek64 convfsync dd ifu-boot.itb of/dev/sdX seek16384 convfsync注意seek的单位是扇区512字节64扇区就是32KB16384扇区就是8MB。烧录前务必确认/dev/sdX是你的目标设备写错盘会直接毁掉主机数据这个坑我见过不止一个人踩。4.2 内核镜像的格式和加载方式RK3588的U-Boot支持多种内核镜像格式最常用的是FIT image.itb它把内核、设备树、initramfs打包在一起U-Boot通过配置里的地址去加载。也可以用传统的Image 单独的设备树dtb。我倾向于用FIT image因为它把内核和设备树的对应关系固化在镜像里减少了U-Boot环境变量配错的风险。生成FIT image需要一个.its配置文件描述各个组件的路径和加载地址。RK3588的内核加载地址通常是0x02080000设备树在0x0a100000附近具体值参考Rockchip的文档。U-Boot的bootargs里必须包含正确的root参数指向你的根文件系统所在的分区和类型。比如从eMMC的第三个分区启动root/dev/mmcblk0p3 rootwait rw如果是用initramfs还要加initrd相关参数。bootargs里一个字符写错内核就找不到rootfs表现是内核panic然后停在VFS: Unable to mount root fs。4.3 rootfs的制作从Ubuntu base到可启动系统Ubuntu 26.10的ARM64 rootfs可以用官方提供的base tarball也可以用debootstrap自己构建。我推荐用官方base tarball因为它的包依赖关系已经处理好省去很多麻烦。拿到tarball后解压到一个目录然后chroot进去做基础配置sudo tar -xpf ubuntu-base-26.10-base-arm64.tar.gz -C rootfs/ sudo cp /usr/bin/qemu-aarch64-static rootfs/usr/bin/ sudo chroot rootfs/chroot之后要做的几件事配置apt源换成ARM64的镜像源、安装必要的包比如systemd、udev、netplan、openssh-server、设置root密码、配置网络。这里有个关键点chroot环境下很多服务不能正常启动所以不要在里面执行systemctl命令等真正启动到板子上再配置。rootfs准备好后把它写入eMMC或SD卡的对应分区。分区布局我一般用第一个分区放引导文件FAT32第二个分区放内核和设备树第三个分区放rootfsext4。ext4分区建议留足空间Ubuntu 26.10装完基础系统加上常用工具10GB起步比较稳妥。4.4 首次启动的调试策略第一次启动大概率不会一次成功。我的调试策略是串口日志优先从BootROM的输出开始看逐级确认BootROM有没有输出没有的话检查启动介质选择和烧录偏移。TPL/SPL有没有输出没有的话检查DDR配置。U-Boot有没有输出有的话看它有没有找到内核镜像。内核有没有输出有的话看它卡在哪一步。内核启动完成后systemd有没有正常拉起没有的话看是哪个服务失败。串口工具用picocom或minicom都行波特率通常是1500000RK3588的调试串口默认是这个非标准波特率不是115200这点很多人第一次会搞错。如果串口输出乱码先确认波特率再确认引脚复用配置。5. 实测中暴露的问题和对应的解决思路5.1 显示输出Mali-G610的驱动适配RK3588的显示子系统在主线内核里的支持是分阶段的。HDMI输出相对成熟DisplayPort和MIPI-DSI的支持要看具体内核版本。我实测下来用主线6.12内核HDMI能正常输出到1080p和4K但刷新率和色彩格式需要根据显示器调整。Mali-G610的GPU驱动分两部分内核态的Panfrost/Panthor驱动和用户态的Mesa。Ubuntu 26.10自带的Mesa版本对Mali-G610的支持已经不错但需要确认内核里的Panfrost驱动被编译进去了并且固件文件mali_csffw.bin放在/lib/firmware/下。缺了固件GPU初始化会失败表现是dmesg里有mali相关的报错图形界面只能用软件渲染非常卡。验证GPU是否工作可以用glmark2-es2跑个分或者看/sys/class/drm/下的设备节点。如果glxinfo或eglinfo报错基本就是驱动或固件的问题。5.2 网络以太网和WiFi的坑RK3588的千兆以太网在主线内核里用stmmac驱动通常能直接工作。但PHY的配置因板子而异有的板子用的是RTL8211有的是其他型号设备树里的PHY地址和复位引脚要写对。如果网口灯不亮先查PHY的电源和复位再查MDIO总线上的地址。WiFi这块比较麻烦因为WiFi模组型号太多AP6275、RTL8822等驱动有的在主线里有的需要额外打补丁。而且WiFi还需要固件文件.bin这些固件不一定在Ubuntu的linux-firmware包里。我的建议是先把有线网络调通用有线网络装好必要的工具再慢慢搞WiFi。5.3 散热和功耗别忽视物理层面RK3588满负荷跑起来发热不小没有散热片的情况下编译大型项目几分钟就会触发降频。我实测过加一个普通的铝制散热片CPU持续满载温度能控制在70度左右不加散热片很快冲到85度以上开始降频编译时间直接翻倍。功耗方面RK3588的典型功耗在5W到15W之间取决于负载和外设。用USB-C供电的话要确保电源能提供足够的电流至少3A否则大负载下会掉电重启。这个现象很容易被误判成软件问题其实是供电不足。5.4 常见启动失败的症状对照症状可能原因排查方向串口无任何输出DDR配置错误、烧录偏移错误检查TPL/SPL、确认烧录位置串口乱码波特率不对、时钟配置错误确认1500000波特率、检查时钟树U-Boot找不到内核镜像格式错误、加载地址错误检查FIT配置、确认bootargs内核panic找不到rootfsroot参数错误、存储驱动缺失检查bootargs、确认eMMC/SD驱动卡在systemdrootfs不完整、服务配置错误看具体失败的服务、检查依赖运行中随机死机电源不稳、regulator配置错误检查供电、核对设备树电源节点这张表是我自己排查问题时总结的大部分启动问题都能通过串口日志定位到具体阶段关键是不要慌按链路一级一级往下查。6. 移植完成后的实际体验和后续可做的事系统跑起来之后我做了几项基础测试来验证稳定性。CPU方面用stress-ng跑满8个核心半小时没有出现死机或降频异常散热到位的前提下。内存方面用memtester测了4GB和8GB的板子通过。存储方面eMMC的读写速度在HS400模式下能到读300MB/s、写200MB/s左右符合预期。网络方面千兆以太网用iperf3测能跑到940Mbps左右基本跑满。Ubuntu 26.10的用户空间体验比旧BSP好很多。apt能直接装到较新的软件包不用自己编译一堆依赖。Docker和containerd跑起来很顺cgroup v2支持完整。Python环境和各种AI框架的安装也比以前省心。后续可以做的事还有不少NPU的驱动和RKNN工具链适配是下一个重点目前主线内核对NPU的支持还在完善中硬件视频编解码VPU的驱动也需要额外配置PCIe和USB 3.0的外设兼容性可以进一步测试。这些我都会在后续的折腾中继续记录。最后分享一个我在整个移植过程中体会最深的点嵌入式移植没有标准答案只有针对你的板子的答案。同一份内核源码在不同板子上表现可能完全不同因为设备树、电源、DDR时序这些板级差异太大了。所以遇到问题不要急着怀疑内核有bug先回头看看你的设备树和硬件配置对不对。串口日志是你最好的朋友学会读日志、定位阶段比记住任何具体命令都重要。