
折腾完一块基于龙芯2K0300的久久派开发板把开发环境和内核升级整条链路跑通之后我最大的感受是国产CPU平台这几年真不是“能不能用”的问题了而是“顺不顺”的问题。龙芯2K0300用的LoongArch指令集和x86/ARM生态完全不同开发环境搭建、内核编译、镜像引导每一步都有自己的一套套路。如果你是第一次上手光看着网上的零散资料很容易卡在工具链、设备树、Uboot启动参数这些环节上。这篇文章记录的是我从零开始搭建久久派开发环境并完成一次内核升级的完整过程。内容包括交叉编译工具链的选择与安装、内核源码的获取与配置、SD卡启动镜像的制作、Uboot引导参数的设置以及升级失败后的排查和回滚。目标读者是把LoongArch板子当ARM板子用、想少踩坑的嵌入式开发者也包括刚入手这块板子、想理解整个开发闭环的新手。按照下面的顺序走一遍基本能把环境跑通内核也能顺利升上去。1. 项目定位与开发环境整体思路1.1 久久派和龙芯2K0300到底适合做什么先理清硬件背景。龙芯2K0300是一颗面向嵌入式场景的SoC内置LoongArch架构的处理器核心主频和功耗控制在比较适合边缘设备、工业控制、教学实验的场景。久久派则是围绕这颗SoC设计的开发板板子上一般会引出串口、网络、USB、TF卡等常用接口整体定位是“能跑Linux、能折腾、成本可控”的小板子。这类板子最大的特征是处理器指令集和常见ARM板不在一个生态。ARM板子上的工具链、内核补丁、启动流程已经高度模板化出了问题随手一搜就有答案。LoongArch平台虽然这几年生态进展很快但很多细节还是需要自己动手验证。比如说交叉编译器的命名、内核defconfig的选择、Uboot引导Image的方式都和x86/ARM的习惯有差异。环境搭建的意义就是把这些差异点逐个确认清楚让后面的开发工作不再被环境问题打断。1.2 为什么推荐“交叉编译”而不是板端编译有人会问久久派既然能跑Linux为什么不能直接在板子上把内核源码下载下来编译理论上是完全可以的只要rootfs里装好了编译器和依赖库。但实际开发中我不太建议这么做。原因是嵌入式板子的存储空间和编译速度都有限内核源码展开后加上编译产生的中间文件动辄几个GBTF卡和内存压力都很大。更重要的是一套开发环境往往要服务多块板子在宿主机上做好交叉编译镜像统一分发效率要高得多。我习惯用一个类比来解释交叉编译宿主机像是后厨板子像是餐厅餐桌。你在后厨按照餐厅的规格把菜做好传菜员再把菜端到餐桌上。这里的“餐厅规格”就是目标CPU架构和系统环境而工具链就是那个既懂后厨又懂餐厅的传菜员。编译时指定的ARCH和CROSS_COMPILE就是在告诉传菜员目的地是LoongArch不是宿主机自己的架构。1.3 环境搭建与内核升级的完整链路拆解一个完整的LoongArch开发环境拆开来看其实是四条链路工具链、根文件系统、引导固件、内核镜像。工具链负责把源码变成可执行程序根文件系统负责提供Linux运行时的目录、库和工具引导固件Uboot负责把内核镜像从存储介质加载到内存内核镜像则是系统真正的核心。内核升级看似只是替换一个镜像实际上牵扯到工具链能否编译出新内核、Uboot能否引导新内核格式、根文件系统能否和内核新驱动兼容。所以这次实操我按照“先搭环境、再编译内核、最后升级验证”的顺序推进每一步都是下一步的前提。2. 核心细节解析与实操要点2.1 工具链选型的几个关键点LoongArch平台目前可以选择的交叉工具链主要有官方提供的预编译版本和发行版仓库里的loongarch64工具链。我在实际操作中优先选择预编译压缩包原因是版本比较新、GCC和binutils配套一致不容易出现编译到一半报版本不兼容的问题。选择工具链时最需要关注的是三点。一是GCC版本不能太低编译较新的内核主线时老版本GCC可能不识别新语法或者缺少特定目标支持。二是工具链必须静态或正确动态链接到目标库否则交叉编译出来的程序在板子上会因为缺少动态库直接启动失败。三是工具链命名规范一般会形如loongarch64-linux-gnu-在使用CROSS_COMPILE时要把这一整串前缀填进去。安装好之后建议先跑一个最简单的命令验证loongarch64-linux-gnu-gcc -v能看到版本号和target信息说明工具链可以正常执行。这一步能过滤掉很多后续问题因为内核编译过程很长如果到一半才发现工具链有问题排查会非常痛苦。2.2 根文件系统内核升级绕不开的基础很多人做内核升级时只盯着内核镜像忽略了根文件系统。实际上内核启动后必须挂载根文件系统才能执行init程序、加载动态库、进入用户态。如果rootfs里缺少某个驱动模块或者文件系统格式与内核配置不匹配板子照样会卡在“VFS: Cannot open root device”的报错上。对久久派这类板子常见的做法是使用官方或社区提供的LoongArch基础rootfs自己再往里面补充工具和库。这里有个容易踩的坑rootfs里的动态库架构必须和CPU架构一致比如宿主机是x86直接复制host端的/bin/bash过去肯定是跑不起来的。所以在搭建环境时时刻记住“工具链决定可执行文件格式rootfs决定运行时环境”两者对齐才能正常工作。2.3 从Uboot到内核的启动链路启动流程是排查问题的核心线索。久久派板子通电后引导固件Uboot先运行随后Uboot根据环境变量找到并加载内核镜像和设备树DTB最后把控制权交给内核。可以把Uboot看作是板子的BIOS设备树是硬件配置清单内核镜像则是操作系统本体。升级内核时必须保证Uboot加载的地址和内核格式能与新版本匹配。常见的做法是通过booti命令启动Image格式的内核同时把DTB放到独立的加载地址。很多启动失败案例其实不是内核编译错了而是Uboot把内核加载到了错误的内存地址或者传递的内核启动参数bootargs里root指向了错误的分区。理解这条链路后看到一个启动日志你就能大致判断问题出在引导阶段、设备树阶段还是挂载rootfs阶段。2.4 串口和网络调试环境的“两条腿”刚开始调试板子时串口是必须优先打通的通道。系统在启动过程中会把所有日志通过串口输出如果串口不通后续所有工作都无法进行。连接串口时我一般使用115200波特率、8数据位、1停止位、无流控的经典参数。接线时注意地线一定要连好波特率不对则会出现乱码现象这点需要优先排除。网络通道同样重要。有了网络之后就可以用TFTP把内核镜像直接传到板子内存中省去反复插拔TF卡的麻烦。更进一步还可以用NFS作为根文件系统实现“宿主机改代码、板子直接运行”的开发模式。网络传输是内核迭代调试中效率提升最明显的手段升级一次内核如果每次都要拔卡、插卡、烧写效率太低了。3. 实操过程与核心环节实现3.1 宿主机环境准备与依赖安装我这里以常见的x86 Linux发行版作为宿主机。第一步是安装内核编译所依赖的软件包不同发行版包名略有差异但下面这些基本跑不掉sudo apt update sudo apt install -y build-essential git wget flex bison bc \ libssl-dev libncurses-dev device-tree-compiler u-boot-tools其中flex和bison用于生成语法解析器bc用于内核配置时的数值计算libssl-dev是编译内核模块必需的device-tree-compiler用来处理设备树u-boot-tools偶尔用于制作镜像资源。这些工具属于典型的基础设施缺哪个后面都会在莫名其妙的地方报错。然后准备工具链目录sudo mkdir -p /opt/loongarch sudo tar -xJf loongarch64-toolchain.tar.xz -C /opt/loongarch export PATH/opt/loongarch/bin:$PATH建议把export PATH写入~/.bashrc否则每次打开新终端都要重新手动指定。工具链目录放在/opt下比较常规权限清晰也不容易被误删。3.2 用测试程序验证工具链在正式编译内核前先做一个最小的冒烟测试确认工具链生成的程序架构正确。新建一个hello.c#include stdio.h int main(void) { printf(hello loongarch\n); return 0; }执行交叉编译并用file查看产物格式loongarch64-linux-gnu-gcc -o hello hello.c file hello如果输出中出现类似“ELF 64-bit LSB executable, LoongArch”的信息说明工具链工作正常。此时编译出的程序并不能在x86宿主机上直接运行它的目标平台是久久派。这个测试程序可以顺便通过TF卡或者scp传到板子上跑一遍验证整个传输和运行链路。3.3 内核源码获取与配置工具链验证通过后开始处理内核源码。可以从上游内核仓库或者其他维护良好的代码仓库获取也可以使用厂商提供的BSP内核源码。我个人建议优先使用维护活跃、版本较新的主线内核原因很简单久经测试的代码往往比临时补丁更稳定后续遇到问题也更容易找到参考资料。进入源码目录后先查看LongArch架构下提供了哪些配置文件ls arch/loongarch/configs/选择对应2K0300或久久派板型的defconfig作为起点。如果没有完全匹配的选一个最接近的通用配置之后再用menuconfig手动调整。配置过程示范如下make ARCHloongarch CROSS_COMPILEloongarch64-linux-gnu- loongarch_defconfig打开图形化配置界面make ARCHloongarch CROSS_COMPILEloongarch64-linux-gnu- menuconfig在配置菜单里优先确认几个关键选项是否开启文件系统EXT4文件系统支持、VFAT支持这对应常见的rootfs和boot分区格式启动参数earlycon和console相关的串口输出支持存储设备USB存储、MMC/SD卡驱动网络板载网卡对应的驱动和协议栈如果不是特别了解某项配置的作用尽量保持defconfig默认选项不要大面积改动。嵌入式调试中最怕的不是功能少而是功能配置和实际硬件不匹配浪费大量时间定位一些“看似无关”的问题。3.4 编译内核与设备树配置完成后开始正式编译。建议导出环境变量避免每条命令都重复写前缀export ARCHloongarch export CROSS_COMPILEloongarch64-linux-gnu- make -j$(nproc) Image dtbs modules其中Image是Linux内核的可引导镜像dtbs是设备树二进制文件modules是内核模块。编译时间与机器性能相关首次全量编译通常需要十几分钟到半小时不等。编译结束后可以在源码目录下看到生成的镜像文件设备树文件一般位于arch/loongarch/boot/dts/相关目录。注意如果编译中遇到“missing sysroot”或者“cannot find -lc”之类的报错优先检查工具链本身是否安装完整而不是急着调内核配置。这类问题通常和CROSS_COMPILE环境变量的前缀配置有关。3.5 制作SD卡引导镜像把编译好的内核和设备树部署到SD卡上需要先对SD卡进行分区。这里以/dev/sdX为例实际操作时请根据宿主机识别到的设备名替换避免误操作覆盖系统盘。分区规划是一个简单的双分区方案第一个分区FAT32大小建议128MiB存放内核镜像快捷与设备树文件第二个分区ext4占剩余空间存放根文件系统创建分区并格式化sudo parted /dev/sdX mklabel msdos sudo parted /dev/sdX mkpart primary fat32 1MiB 128MiB sudo parted /dev/sdX mkpart primary ext4 128MiB 100% sudo mkfs.vfat /dev/sdX1 sudo mkfs.ext4 /dev/sdX2挂载后把内核镜像和设备树拷贝到第一分区把rootfs解压到第二分区。特别注意拷贝完成后要执行sync避免缓存未落盘就拔卡导致数据损坏。sudo mount /dev/sdX1 /mnt/boot sudo mount /dev/sdX2 /mnt/rootfs sudo cp arch/loongarch/boot/Image /mnt/boot/vmlinuz sudo cp arch/loongarch/boot/dts/.../*.dtb /mnt/boot/board.dtb sudo tar -xJf rootfs.tar.xz -C /mnt/rootfs sudo sync内核模块的安装位置必须是rootfs对应的目录而不是宿主机root目录sudo make modules_install INSTALL_MOD_PATH/mnt/rootfs3.6 设置Uboot引导参数SD卡准备好之后把板子接上串口和网口插入SD卡上电。在串口终端中按提示进入Uboot命令行重点检查环境变量中关于加载地址和启动参数的部分。参照下面这组配置setenv bootargs consolettyS0,115200 root/dev/mmcblk0p2 rw rootwait setenv loadk load mmc 0:1 0x90000000 vmlinuz setenv loadd load mmc 0:1 0x90100000 board.dtb setenv bootcmd run loadk; run loadd; booti 0x90000000 - 0x90100000 saveenv这里的加载地址需要以实际Uboot版本和板级配置为准。booti后面第一个地址是内核镜像加载地址第二个地址是DTB地址中间的-表示没有单独的initramfs。设置完bootcmd后板子在下次上电时就会自动从SD卡加载并引导新内核。老手会习惯先把bootcmd设置为空或保留一个可中断的等待逻辑防止新内核起不来时板子无限重启失去手动干预的机会。3.7 内核升级后的验证与回滚完成引导后进入系统第一件事是确认内核版本uname -a看到新的内核版本号说明升级基本成功了。接着检查启动日志中是否存在驱动加载错误dmesg | grep -i error dmesg | grep -i fail网卡是否识别、SD卡是否挂载、USB存储是否可用等关键外设功能也要逐一确认。如果新内核有问题不要慌回滚路径早在升级前就该准备好。最简单的做法是在之前把旧内核和旧设备树备份在boot分区的backup/目录下出问题时重新拷贝回原文件名重启即可恢复。升级完成且稳定运行后再考虑清理备份避免boot分区空间被反复占满。4. 常见问题与排查技巧实录4.1 串口无输出或乱码这是遇到频率最高的问题。无输出的常见原因包括接线接错或者串口工具选错设备节点。乱码的原因则一般是波特率不匹配。久久派默认控制台波特率通常是115200但也不能想当然建议用dmesg | grep tty查看Uboot输出确认实际数值。如果接的是USB转串口工具先确认宿主机识别到的设备名比如/dev/ttyUSB0并确保串口工具软件使用的是8N1模式。4.2 内核启动卡死在“Starting kernel”卡在这个位置基本说明Uboot已经把控制权交给了内核但内核没有正常输出。排查方向有两个一是设备树与内核不匹配导致内核在早期初始化阶段就停止二是内核中串口console配置没有开启或者参数不对。可以在bootargs里临时加入earlycon参数这样能看到更早期的内核输出信息定位卡死位置。4.3 根文件系统挂载失败出现“VFS”报错日志中出现类似“VFS: Cannot open root device”的信息时问题不在内核镜像而在rootfs这一侧。先检查bootargs里的root参数是否指向正确的分区比如SD卡第二分区的设备节点是否为/dev/mmcblk0p2。接着确认内核中是否编译了对应文件系统的支持。如果rootfs是ext4格式内核必须包含EXT4支持否则即使分区存在也无法挂载。4.4 网络不通或USB设备无法识别这类问题大多不是硬件故障而是内核模块没有正确加载。排查方法是用lsmod查看模块列表用dmesg查看设备是否被识别。如果对应的驱动没有编译进内核需要回到内核源码目录在menuconfig中找到相关驱动并重新编译。少数情况下USB设备无法识别是因为没有开启USB存储支持项这类配置项一般在设备驱动菜单里和具体硬件一对一核对即可。4.5 常见问题速查表现象可能原因排查顺序串口完全无输出接线错误、串口工具选错设备检查设备节点、接线、Uboot是否运行串口输出乱码波特率不匹配统一为115200 8N1卡在Starting kernelDTB不匹配、earlycon未开启加earlycon核对DTB来源VFS挂载失败root参数错误、文件系统驱动缺失检查bootargs、内核配置EXT4等网卡无法工作驱动未编译或模块未加载dmesg看驱动信息重新编译对应驱动内核版本未变化镜像未实际更新、引导了旧备份核对boot分区时间戳、重新配置bootcmd4.6 一次内核启动卡死的排查复盘前段时间我帮同事调一块同样项目环境的板子现象是烧写新内核后卡死在“Starting kernel”。一开始怀疑是编译配置有问题反复检查了很久后来在Uboot命令行里一步步确认每个环节发现是bootargs中root写的是旧分区的设备节点。新内核使用的rootfs放到了第二分区而旧参数指向第一分区第一分区是FAT格式内核自然挂载失败。改完参数后一次启动成功。这个经历让我养成了一个习惯任何内核升级后启动异常第一件事不是怀疑内核源码而是检查引导参数和实际分区布局是否一致。结尾的几点个人经验整条环境链路跑下来我个人体会最深的不是某一项命令而是“环境搭建、内核升级”这两个目标其实是对整个LoongArch开发流程的一次完整检验。工具链、rootfs、Uboot、内核每一环都正常最终才能看到新内核的启动日志。这也意味着如果你只是照着命令敲一遍可能一切顺利但你一旦明白了每个环节的作用后续做驱动开发或者BSP定制时就有了清晰的问题定位能力。最后分享一个小建议把这次成功验证过的内核配置文件和Uboot环境变量备份到自己的配置仓库里。这样下次重新搭建环境或者换一块新板子就能基于这次跑通的配置快速起步。内核升级不是一个一次性的操作它往往是你接下来所有板级开发的基础基础打得稳后面的工作才会顺。