ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

全志芯片TF/SD启动盘制作:从U-Boot编译到Linux内核部署全解析

全志芯片TF/SD启动盘制作:从U-Boot编译到Linux内核部署全解析 1. 项目概述为什么需要自己制作TF/SD启动盘玩过全志芯片开发板的朋友尤其是像F1C100s、V3s、H3、A64这些热门型号的肯定都经历过一个阶段拿到一块空板子或者把eMMC/NAND刷坏了怎么让它重新“活”过来官方的PhoenixSuit或LiveSuit工具固然方便但它通常依赖USB OTG连接并且刷入的是厂商打包好的固件。当你需要深度定制内核、更换设备树、调试uboot或者只是想用上主线内核的最新特性时依赖官方工具和固件就显得束手束脚了。这时候一张能直接从TF卡或SD卡启动的“启动盘”就成了开发者的救命稻草和效率神器。它把uboot、内核、设备树、根文件系统都放在一张卡上插卡即启动拔卡恢复原状。编译测试新内核直接替换卡里的zImage文件。调整uboot环境变量在启动时按个键就能进入命令行。整个过程完全独立于板载存储安全、快速、可重复是进行系统级开发和调试的黄金标准流程。这个项目要做的就是彻底搞懂如何从零开始为全志系列芯片制作一个基于主线u-boot和Linux内核的TF/SD卡启动盘。我们不止步于“照着命令敲”更要深挖每一步背后的逻辑为什么分区表要这么布局uboot的SPL是怎么被芯片识别的内核和设备树如何匹配理解了这些你就能应对各种奇奇怪怪的板子和需求而不是只会套用一个固定的脚本。2. 核心原理与准备工作拆解在动手之前我们必须把全志芯片的启动流程和存储介质结构搞清楚。这就像盖房子的蓝图流程错了后面怎么砌砖都是白搭。2.1 全志芯片的启动顺序解析全志ARMv7/AArch64芯片如H3, A64, R328等通常采用一种类似“二级引导”的机制这对于从可移动介质启动至关重要固化ROM代码芯片内部有一小块掩膜ROM出厂时就烧写好了。上电后它最先运行其任务非常简单从预定的几个外设接口如SDC0, SPI0, eMMC的固定位置通常是存储介质最开始的8KB或16KB空间寻找一段有效的代码并执行。对于SD/TF卡这个固定位置就是扇区0开始的位置。SPL (Secondary Program Loader)这就是我们uboot编译产物中的u-boot-sunxi-with-spl.bin。ROM代码会把它加载到内部SRAM中运行。由于SRAM空间有限可能只有32KB或64KB这个阶段的uboot即SPL功能精简主要初始化DRAM内存和更基础的时钟。完整u-bootSPL初始化好DRAM后会将存储介质上另一块更大、功能更完整的uboot镜像即u-boot.itb或旧的u-boot.img加载到DRAM中然后跳转执行。这个完整的uboot会初始化更多外设加载环境变量解析boot.scr脚本或直接执行bootcmd命令。Linux内核uboot最后的工作就是将内核镜像zImage或Image、设备树 blob.dtb文件、以及可选的初始RAM磁盘initramfs加载到内存指定地址并跳转到内核入口点完成启动权的交接。我们的制作核心就是按照这个流程把正确的文件放到TF卡的正确位置上。2.2 工具链与源码准备工欲善其事必先利其器。你需要一个Linux开发环境物理机或虚拟机均可并准备好以下工具和源码交叉编译工具链你的电脑是x86_64架构要编译运行在ARM架构上的程序就需要交叉编译器。推荐使用Linaro或Arm官方的GCC工具链。例如对于ARMv732位# 例如安装arm-linux-gnueabihf-工具链 sudo apt-get install gcc-arm-linux-gnueabihf对于ARMv864位# 例如安装aarch64-linux-gnu-工具链 sudo apt-get install gcc-aarch64-linux-gnu安装后使用arm-linux-gnueabihf-gcc -v或aarch64-linux-gnu-gcc -v验证。主线u-boot源码从官方仓库获取。主线uboot对全志芯片的支持已经很完善了。git clone https://source.denx.de/u-boot/u-boot.git cd u-boot # 或者使用镜像站git clone https://github.com/u-boot/u-boot.git主线Linux内核源码同样从官方仓库获取。git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git # 建议切换到一个稳定的长期支持版本如 git checkout v6.1.y设备树源码设备树文件.dts通常在内核源码目录的arch/arm/boot/dts/或arch/arm64/boot/dts/allwinner/下。编译内核时会同时编译出二进制的.dtb文件。根文件系统可以选择预编译的镜像如Debian/Ubuntu base也可以使用BusyBox自己构建一个最小的initramfs。对于初学者下载一个现成的ARM架构的rootfs tarball是最快的方式。例如从Debian或Ubuntu官方获取。必要的工具parted或fdisk分区mkfs格式化dd烧写镜像mount挂载分区。这些通常在Linux系统中已预装。注意源码的版本匹配很重要。较新的uboot可能依赖较新内核的DTB格式建议在项目初期选择一个已知稳定的组合例如uboot 2023.01 linux 6.1 LTS。避免盲目使用master分支的最新代码以免遇到未修复的兼容性问题。3. TF卡分区与布局设计详解这是制作启动盘最关键的一步布局决定了芯片ROM和uboot能否找到它们需要的东西。一张标准的全志启动TF卡通常包含以下部分其物理布局如下图所示------------------------------------------------------------------------------- | 8KB~32KB | 约1MB ~ 几MB | 剩余空间 | | (SPL Padding) | (完整U-Boot, 环境变量等) | (内核、根文件系统) | ------------------------------------------------------------------------------- 扇区0 扇区16/32 分区1起始扇区 (如20480) (分区表) 分区2起始扇区...全志启动TF卡物理布局示意图1. 未分区区域偏移0开始 *作用存放SPL和完整uboot镜像。芯片ROM会从这里读取最初的引导代码。 *操作使用dd命令直接写入原始二进制数据不涉及文件系统。2. 第一个分区FAT32通常挂载为/boot *作用存放Linux内核镜像zImage、设备树二进制文件.dtb、uboot脚本boot.scr以及可能的额外固件。FAT32格式是因为uboot对其有良好的原生支持无需复杂的驱动即可读写。 *大小通常32MB到128MB足矣足够存放多个内核和DTB用于测试。3. 第二个分区EXT4挂载为根目录/ *作用存放完整的根文件系统rootfs包含操作系统所有的库、应用和配置文件。 *大小占用TF卡剩余的全部空间。为什么不用一个分区因为uboot在加载内核阶段需要能够读取内核文件。如果内核放在EXT4分区uboot需要内置EXT4文件系统驱动这虽然可能但会增加uboot的复杂度和体积。而使用一个独立的、uboot原生支持的FAT分区来放内核是最可靠、最通用的做法。实操步骤使用parted进行分区假设你的TF卡设备是/dev/sdb务必用lsblk命令确认切勿搞错。# 1. 清除旧分区表创建新的GPT或MSDOS分区表。全志平台通常用MSDOSMBR即可。 sudo parted /dev/sdb --script mklabel msdos # 2. 创建第一个FAT32分区boot分区。 # 从第20480个扇区开始即保留约10MB空间给前面的uboot分区大小设为128MiB。 sudo parted /dev/sdb --script mkpart primary fat32 20480s 128MiB # 将第一个分区标记为“可启动”虽然全志不依赖这个标志但这是个好习惯。 sudo parted /dev/sdb --script set 1 boot on # 3. 创建第二个EXT4分区rootfs分区占用所有剩余空间。 sudo parted /dev/sdb --script mkpart primary ext4 128MiB 100% # 4. 格式化分区。 sudo mkfs.vfat -n BOOT /dev/sdb1 sudo mkfs.ext4 -L ROOTFS /dev/sdb2重要提示20480s这个起始扇区值10MB是一个经验值它必须大于你将要写入的u-boot-sunxi-with-spl.bin文件的大小通常只有几百KB。预留10MB或16MB是安全且常见的做法确保了uboot区域不会被分区表覆盖。4. 编译与配置主线U-Boot全志主线uboot的配置和编译已经相当标准化。这里以常见的Allwinner H3芯片用在Orange Pi PC等板子为例。# 进入u-boot源码目录 cd /path/to/u-boot # 1. 清理旧编译产物如果是首次编译可跳过 make distclean # 2. 选择正确的配置文件。 # 对于H3芯片常用的配置是 orangepi_pc_defconfig。其他板子请查阅 configs/ 目录下的 *_defconfig 文件。 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- orangepi_pc_defconfig # 3. 启动图形化配置可选用于微调。 # 你可以在这里启用/禁用一些功能如USB、网络、文件系统支持等。对于基础启动默认配置通常足够。 # make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- menuconfig # 4. 开始编译。 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- -j$(nproc)编译成功后关键产出文件在源码目录下u-boot-sunxi-with-spl.bin这就是我们需要烧写到TF卡最前端的SPLU-Boot组合镜像。它包含了ROM代码要加载的初始程序。u-boot.itb或旧版本的u-boot.img这是完整的U-Boot镜像会被SPL加载到内存中执行。配置要点解析ARCH指定目标CPU架构arm对应32位ARMv7arm64对应64位AArch64。CROSS_COMPILE指定交叉编译工具链的前缀。确保与你安装的工具链匹配。-j$(nproc)使用所有CPU核心并行编译加快速度。5. 烧写U-Boot至TF卡预留区现在将编译好的SPLU-Boot镜像写入TF卡开头的保留区域。这个操作会覆盖该区域的所有数据但不会影响我们之后创建的分区因为分区是从靠后的扇区开始的。# 假设TF卡是 /dev/sdb 镜像文件是 u-boot-sunxi-with-spl.bin sudo dd ifu-boot-sunxi-with-spl.bin of/dev/sdb bs1k seek8 convfsync命令参数详解if输入文件即你的镜像。of输出设备即TF卡千万不能写成分区如sdb1。bs1k以1KB为单位进行读写平衡效率与安全性。seek8关键参数。表示从输出设备开头跳过8个bs即8KB再开始写入。这是因为全志芯片的ROM代码通常从第8KB有些芯片是16KB或32KB处开始寻找有效指令。seek参数确保了我们的SPL被写入了正确的位置而不会覆盖掉分区表分区表通常在第0扇区即第一个512字节。convfsync确保数据完全写入设备后再返回避免缓存导致的数据不完整。实操心得seek的值因芯片而异。对于大多数常见的全志芯片H3, A64, H5, H6等seek8是安全的。如果你不确定查阅芯片的特定文档或查看社区中同类板子的配置。一个错误的seek值会导致芯片ROM无法找到引导代码从而启动失败。6. 编译与配置主线Linux内核内核编译比uboot稍复杂因为需要配置的选项更多。我们的目标是生成一个能驱动基础硬件的最小内核。cd /path/to/linux-stable # 1. 清理并应用默认配置。以ARM架构为例。 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- defconfig # 对于特定板子可能有现成的配置文件如 sunxi_defconfig 适用于所有全志ARMv7芯片。 # make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- sunxi_defconfig # 2. 进入图形化配置界面进行定制重要。 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- menuconfig在menuconfig中你需要关注和确保以下配置使用/键搜索CPU类型System Type - ARM system type - Allwinner SoC Support选择你的具体芯片型号如Allwinner sun8i Family下的Allwinner H3。设备树支持Device Drivers and board support - Device Tree and Open Firmware support必须启用。串口控制台Device Drivers - Character devices - Serial drivers确保8250/16550 and compatible serial support和Console on 8250/16550 and compatible serial port启用。这是你通过串口调试的命脉。SD/MMC驱动Device Drivers - MMC/SD/SDIO card support确保Allwinner sunxi SD/MMC Host Controller support启用。文件系统File systems下确保DOS/FAT/NT Filesystems中的VFAT (Windows-95) fs support启用用于读取boot分区。同时启用The Extended 4 (ext4) filesystem支持用于根文件系统。网络驱动如果你的板子有网络且需要找到对应的以太网或Wi-Fi驱动并启用。配置完成后保存退出。# 3. 开始编译内核和设备树。 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- -j$(nproc) zImage dtbs # 如果编译成功关键产出文件在 # arch/arm/boot/zImage - 压缩的内核镜像 # arch/arm/boot/dts/*.dtb - 编译好的设备树二进制文件找到对应你板子的那个如sun8i-h3-orangepi-pc.dtb。7. 组装启动盘填充Boot和Rootfs分区现在TF卡已经有了分区表和uboot我们需要把内核、设备树和根文件系统放进对应的分区。# 1. 挂载TF卡的两个分区。假设挂载到 /mnt/boot 和 /mnt/rootfs sudo mkdir -p /mnt/{boot,rootfs} sudo mount /dev/sdb1 /mnt/boot sudo mount /dev/sdb2 /mnt/rootfs # 2. 复制内核和设备树到boot分区。 sudo cp /path/to/linux-stable/arch/arm/boot/zImage /mnt/boot/ sudo cp /path/to/linux-stable/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dtb /mnt/boot/ # 你可以重命名设备树文件为更通用的名字方便uboot脚本引用例如 sudo cp sun8i-h3-orangepi-pc.dtb /mnt/boot/dtbs/ # 3. 创建U-Boot脚本文件可选但推荐。 # boot.scr是一个包含U-Boot命令的脚本告诉U-Boot如何加载内核。 # 首先创建一个文本文件 boot.cmd内容如下 cat EOF | sudo tee /mnt/boot/boot.cmd # 设置内核加载地址和设备树加载地址 setenv loadaddr 0x42000000 setenv fdt_addr_r 0x43000000 # 从第一个FAT分区mmc 0:1加载内核和设备树 load mmc 0:1 \${loadaddr} zImage load mmc 0:1 \${fdt_addr_r} dtbs/sun8i-h3-orangepi-pc.dtb # 设置内核启动参数 setenv bootargs consolettyS0,115200 earlyprintk root/dev/mmcblk0p2 rootwait rw # 启动内核 bootz \${loadaddr} - \${fdt_addr_r} EOF # 然后使用U-Boot工具mkimage将这个文本文件编译成U-Boot可识别的boot.scr。 # 你需要先安装u-boot-tools包或者使用你编译好的uboot源码里的tools/mkimage。 sudo mkimage -C none -A arm -T script -d /mnt/boot/boot.cmd /mnt/boot/boot.scr # 4. 解压根文件系统到rootfs分区。 # 假设你有一个名为 rootfs.tar.gz 的根文件系统压缩包。 sudo tar -xzf /path/to/rootfs.tar.gz -C /mnt/rootfs --numeric-owner # --numeric-owner 参数很重要它保持压缩包内文件的原始用户/组ID避免权限问题。 # 5. 同步并卸载分区。 sudo sync sudo umount /mnt/boot sudo umount /mnt/rootfs至此一张完整的全志主线启动TF卡就制作完成了。8. 上电测试与深度调试技巧将制作好的TF卡插入开发板连接串口调试线USB to TTL使用串口终端工具如minicom,picocom,screen或Windows下的Putty、MobaXterm打开对应的串口如/dev/ttyUSB0波特率通常设为115200。给开发板上电你应该在串口终端看到uboot的启动日志接着是内核的启动信息。如果成功最后会进入登录提示符。常见问题与排查实录问题上电后串口无任何输出。排查检查串口线连接是否正确TX接RXRX接TXGND接GND。确认串口终端软件配置端口、波特率115200、数据位8、停止位1、无流控。最可能的原因U-Boot没有正确烧写或seek值不对。用hexdump命令检查TF卡开头部分是否有数据sudo hexdump -C /dev/sdb | head -50你应该能看到非零的二进制数据。如果全是00或ff说明dd命令没写进去或设备号错了。问题U-Boot启动后卡住提示MMC: no card present或类似错误。排查这通常是U-Boot的SD/MMC驱动问题或设备树配置不对。确认你编译U-Boot时使用的defconfig是否匹配你的板子。检查内核设备树是否正确。有时主线内核的设备树节点名或兼容性字符串与U-Boot预期有细微差别。尝试在U-Boot启动时按任意键进入命令行手动输入mmc list和mmc dev 0查看是否能识别到SD卡。问题U-Boot能启动但加载内核时失败提示Invalid kernel image或Wrong Ramdisk Image Format。排查确认你编译的内核镜像格式是否正确。ARMv7通常用zImage压缩镜像ARMv8用Image非压缩镜像。使用file命令检查file arch/arm/boot/zImage。检查boot.scr或bootcmd中的内核加载地址loadaddr是否与内核编译时指定的入口地址匹配。对于ARM Linux0x42000000或0x40008000是常见的地址。确认设备树加载地址fdt_addr_r没有与内核加载地址重叠。问题内核Panic提示VFS: Unable to mount root fs或Please append a correct root boot option。排查这是根文件系统挂载失败。检查内核命令行参数root/dev/mmcblk0p2指定了根分区是SD卡的第二个分区。确认分区号是否正确。在U-Boot中可以用part list mmc 0查看分区表。检查根文件系统确认rootfs分区已正确格式化ext4并解压了完整的文件系统。可以重新挂载到电脑检查/mnt/rootfs目录下是否有bin,sbin,lib,etc等目录。检查内核配置确保内核编译时包含了对应文件系统ext4的驱动并且是编译进内核*而不是模块M。一个高级调试技巧使用U-Boot网络加载tftp当频繁修改内核进行测试时反复烧写TF卡效率很低。可以配置U-Boot通过TFTP网络加载内核和DTB。在开发主机上搭建TFTP服务器将zImage和.dtb文件放入TFTP目录。确保开发板和主机在同一局域网且U-Boot网络驱动正常需编译时启用。在U-Boot命令行中设置服务器IP和本机IPsetenv serverip 192.168.1.100 # 你的主机IP setenv ipaddr 192.168.1.101 # 开发板IP使用tftp命令加载tftp ${loadaddr} zImage tftp ${fdt_addr_r} sun8i-h3-orangepi-pc.dtb然后使用bootz命令启动。这样你只需要在主机上编译好内核U-Boot就能直接从网络获取极大提升调试效率。制作全志主线启动盘的过程本质上是对嵌入式Linux启动链的深度实践。从芯片ROM的固执寻址到SPL的轻量初始化再到完整uboot的灵活引导最后到内核的接管与系统的运行每一步都环环相扣。当你亲手完成一次并理解了每个文件、每个命令、每个地址背后的意义你就掌握了让一块“砖头”起死回生的核心能力。这张小小的TF卡不仅是启动介质更是你通往底层系统自由定制的大门钥匙。
返回列表