1. ARM64嵌入式平台开发概述在物联网和边缘计算设备爆炸式增长的今天ARM64架构凭借其出色的能效比和性能表现已经成为嵌入式开发的首选平台。不同于x86架构的通用计算场景嵌入式系统往往需要在资源受限的环境中运行这就要求开发者对系统进行深度定制和优化。我曾经在一个智能家居网关项目中使用Rockchip RK3399平台当时需要将一个完整的Linux系统裁剪到只有32MB存储空间。这个过程让我深刻体会到从内核编译到构建最小根文件系统每一步都需要精心设计和权衡。比如为了节省那几百KB的空间我不得不反复测试哪些内核模块可以安全移除哪些又是系统运行所必需的。ARM64平台与传统的ARM32相比最大的优势在于它支持更大的物理地址空间48位和更先进的指令集。但在嵌入式环境中我们通常不会用到全部功能。以RK3399为例这款芯片采用双核Cortex-A72四核Cortex-A53的big.LITTLE架构但在很多物联网应用中可能只需要启用其中的小核就能满足需求。2. 交叉编译环境搭建2.1 工具链选择与安装搭建交叉编译环境是ARM64开发的第一步。我强烈建议使用官方提供的工具链而不是自己编译这样可以避免很多兼容性问题。对于Ubuntu 20.04系统安装ARM64交叉编译器只需要一条命令sudo apt-get install gcc-aarch64-linux-gnu g-aarch64-linux-gnu这个命令会安装完整的工具链包括编译器、链接器和调试工具。安装完成后可以通过以下命令验证aarch64-linux-gnu-gcc --version在实际项目中我发现工具链版本与内核版本的匹配非常重要。曾经遇到过一个案例使用较新的工具链编译旧版内核时出现了奇怪的运行时错误。后来发现是工具链的默认编译选项与内核不兼容通过添加-mcpucortex-a53参数才解决问题。2.2 开发环境配置除了基本的编译工具还需要一些辅助工具sudo apt-get install build-essential libncurses5-dev bison flex libssl-dev这些软件包提供了内核配置所需的库和工具。特别是libncurses5-dev它是make menuconfig界面依赖的库。我曾经在一个干净的Docker环境中编译内核时就因为缺少这个包导致配置界面无法正常显示。对于嵌入式开发我习惯使用distcc分布式编译来加快编译速度。具体做法是在多台机器上部署相同的工具链然后通过以下命令启动编译export DISTCC_HOSTSlocalhost 192.168.1.2 192.168.1.3 make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- -j$(distcc -j) CCdistcc aarch64-linux-gnu-gcc3. Linux内核编译实战3.1 内核源码获取与配置获取内核源码有两种方式一是从kernel.org下载稳定版本二是使用芯片厂商提供的定制内核。对于RK3399这类主流平台我建议先尝试官方内核wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.6.tar.xz tar -xJf linux-5.15.6.tar.xz cd linux-5.15.6配置内核时defconfig是个不错的起点make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- defconfig但对于嵌入式系统我们需要进一步精简配置。通过make menuconfig进入配置界面后有几个关键点需要注意在General setup中关闭不需要的调试选项和内核特性在Boot options中设置合适的initramfs配置在Device Drivers中只保留目标硬件需要的驱动我曾经犯过一个错误为了追求极致精简把所有的USB驱动都移除了。结果发现开发板需要通过USB转串口调试最后不得不重新编译内核。3.2 内核编译与优化编译内核的基本命令很简单make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- -j8但要让生成的内核更小、更快还需要一些技巧使用-Os优化选项代替默认的-O2make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- KCFLAGS-Os -j8启用内核压缩 在配置中选择Kernel compression mode为LZ4可以获得较好的压缩比和解压速度平衡移除不必要的调试信息make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- INSTALL_MOD_STRIP1 modules_install编译完成后关键文件位于arch/arm64/boot/Image- 内核镜像arch/arm64/boot/dts/rockchip/- 设备树文件4. BusyBox根文件系统构建4.1 BusyBox编译与配置BusyBox是嵌入式系统的瑞士军刀它在一个可执行文件中实现了数百个常用命令。下载和编译BusyBox的步骤如下wget https://busybox.net/downloads/busybox-1.34.1.tar.bz2 tar -jxf busybox-1.34.1.tar.bz2 cd busybox-1.34.1配置时最关键的是选择静态编译make CROSS_COMPILEaarch64-linux-gnu- menuconfig在Settings子菜单中勾选Build static binary (no shared libs)。这样可以避免依赖动态库简化系统部署。我曾经遇到过一个棘手的问题静态编译的BusyBox在某些平台上会出现段错误。后来发现是工具链的bug换成更新的版本就解决了。这也提醒我们嵌入式开发中工具链的稳定性非常重要。4.2 根文件系统结构创建BusyBox编译安装后会在_install目录下生成基本文件结构。但一个可用的根文件系统还需要更多内容cd _install mkdir -p etc/init.d dev proc sys tmp mnt创建基本的初始化脚本etc/init.d/rcS#!/bin/sh mount -t proc proc /proc mount -t sysfs sysfs /sys mount -t tmpfs tmpfs /tmp echo /sbin/mdev /proc/sys/kernel/hotplug mdev -s这个脚本做了三件事挂载虚拟文件系统(proc, sysfs, tmpfs)设置设备节点自动创建扫描并创建设备节点别忘了给脚本添加执行权限chmod x etc/init.d/rcS5. 系统镜像制作与测试5.1 制作根文件系统镜像有了完整的根文件系统目录后可以将其打包成镜像文件dd if/dev/zero ofrootfs.ext3 bs1M count32 mkfs.ext3 rootfs.ext3 mkdir fs sudo mount -o loop rootfs.ext3 ./fs sudo cp -rf ./_install/* ./fs sudo umount ./fs这个流程创建了一个32MB的ext3文件系统镜像。在实际项目中大小需要根据实际需求调整。我曾经在一个项目中为了节省空间使用了ext2文件系统但后来发现断电时偶尔会出现文件损坏最终还是换回了带日志的ext3。5.2 制作可启动镜像对于RK3399平台需要准备以下文件Image内核镜像rk3399.dtb设备树文件extlinux.conf启动配置文件创建启动目录结构mkdir -p boot/extlinux编写启动配置文件boot/extlinux/extlinux.conflabel linux kernel /Image fdt /rk3399.dtb append earlyconuart8250,mmio32,0xff1a0000 root/dev/mmcblk0p1 rootwait然后使用genext2fs工具制作启动镜像genext2fs -b 32768 -d boot -i 8192 -U boot.img5.3 系统烧录与调试使用Rockchip提供的工具烧录镜像sudo rkdeveloptool db rk3399_loader_v1.25.126.bin sudo rkdeveloptool wl 0x8000 boot.img sudo rkdeveloptool wl 0x40000 rootfs.ext3 sudo rkdeveloptool rd烧录完成后系统应该能够正常启动。如果遇到问题可以通过串口调试输出查找原因。常见的启动问题包括内核崩溃检查设备树是否正确内存参数是否匹配卡在启动界面检查根文件系统路径是否正确提示无法运行init检查BusyBox是否静态编译或者尝试添加init/bin/sh调试在一个实际项目中我遇到了内核无法挂载根文件系统的问题。经过排查发现是内核缺少ext4文件系统支持。这个教训让我明白即使是看似简单的配置也需要仔细检查。