1. 项目概述:为什么T113-S3的Linux移植不是“照着文档抄一遍”就能跑起来的事
全志T113-S3这颗芯片,最近在国产嵌入式开发圈里热度很高——它不是那种动辄几十美金的高端SoC,而是真正面向工业控制、智能终端、边缘网关这类对成本、功耗、长期供货有硬性要求场景的务实选择。双核Cortex-A7 + Mali-400 MP2 GPU + 硬件编解码能力,配合全志一贯成熟的BSP支持,让它成了很多中小团队做国产化替代时的第一块“试验田”。但问题就出在这儿:官方SDK里给的demo镜像能跑,自己从零构建一个最小系统却频频卡在串口没输出、内核panic、设备树加载失败这些地方。我去年帮三家客户做T113-S3的定制化移植,最深的体会是:T113-S3的Linux移植,本质是一场对硬件抽象层(HAL)与软件启动链路(Boot Chain)双重理解的实战考试,而不是一次简单的“烧写+启动”操作。它的核心难点不在内核源码本身,而在于你是否真正看懂了BootROM → U-Boot → Linux Kernel → RootFS这条链路上每一环的握手协议、寄存器配置边界和时序约束。比如,很多人以为U-Boot只是个“加载器”,但在T113-S3上,它必须精确完成DDR初始化序列(包括ZQ校准、ODT配置、时序参数微调),稍有偏差,内核连第一条printk都打不出来;再比如,设备树里一个GPIO引脚的status = "okay"写成"ok",整个I2C总线就直接失联——这种细节,在官方文档里往往只用一行带过,但实际调试中可能耗费你两天时间。所以这篇内容,不讲泛泛而谈的“Linux移植流程”,而是聚焦T113-S3这一颗具体芯片,把从焊接完PCB板子开始,到看到/ #提示符出现为止,所有真实踩过的坑、验证过的参数、必须手敲的命令,掰开揉碎讲清楚。适合已经熟悉ARM基础概念、能看懂原理图、愿意对着寄存器手册逐字比对的工程师,也适合刚从STM32转过来、想系统理解Linux启动机制的嵌入式新人。你不需要记住所有寄存器地址,但必须明白为什么这个地址要配这个值,以及配错之后示波器上会看到什么波形。
2. 硬件平台与启动链路深度拆解:T113-S3的“心脏节拍器”到底怎么工作
2.1 T113-S3启动流程的四个不可跳过的物理阶段
T113-S3的启动不是软件代码的线性执行,而是由硬件状态机严格驱动的四段式物理过程。理解这个底层逻辑,是后续所有调试的前提。我把它比喻成一台老式机械钟表的发条上弦过程:BootROM是主发条盒,U-Boot是擒纵机构,Kernel是摆轮游丝,RootFS则是钟面刻度——任何一个环节的齿轮咬合不到位,整台钟就停摆。
第一阶段:BootROM固件(ROM Code)——芯片出厂即固化,你无法修改,但必须敬畏
这是T113-S3上电后执行的第一段代码,存储在芯片内部ROM中,出厂即固化,用户完全不可擦写。它的核心任务只有两个:一是检测启动介质(SD卡、eMMC、SPI Nor Flash、USB Device),按预设优先级(通常是SD卡 > eMMC > SPI Nor)寻找合法的启动头(Boot Header);二是将启动头指定的第二阶段引导程序(即U-Boot SPL或完整U-Boot)从介质中拷贝到片上SRAM(约128KB)并跳转执行。关键点在于:BootROM对启动头格式有极其严格的校验规则。例如,SD卡启动时,它只认取前512字节(MBR扇区)中特定偏移位置(0x2000)的Magic Number(固定为0x4E4F4954,ASCII为"NOIT"),且要求该位置后的校验和字段(CRC32)必须与前面数据计算结果完全一致。我曾遇到一个案例:客户用Windows磁盘管理工具对SD卡做了“快速格式化”,导致MBR扇区被清零,BootROM找不到Magic Number,直接进入USB Device模式(表现为板子上电后USB端口被识别为一个未知设备),死活不走SD卡路径。解决方法?用dd命令从官方SDK里提取原始MBR镜像重新写入:sudo dd if=sdk/tools/sd_fusing/t113-s3-mbr.bin of=/dev/sdb bs=512 seek=0 conv=notrunc。注意seek=0是关键,conv=notrunc防止清空整个SD卡。
第二阶段:U-Boot SPL(Secondary Program Loader)——轻量级“探路者”,专攻DDR初始化
SPL是U-Boot的精简版,通常小于64KB,目标是完成最核心的硬件初始化,尤其是DRAM控制器。T113-S3的DDR控制器支持LPDDR2/LPDDR3,其初始化序列复杂度远超普通SDRAM。SPL必须精确配置以下寄存器组:
DDR_PHY_CTL0~3:控制PHY层基本参数,如ODT(On-Die Termination)阻值、ZQ校准使能、DQS延迟;DDR_TIMING_CFG0~3:定义关键时序参数,如tRCD(RAS to CAS Delay)、tRP(Row Precharge Time)、tRAS(Active to Precharge Delay)。这些值不是凭空猜测,必须根据你所用的LPDDR3颗粒(如三星K4E6E304EC)的Datasheet中“Operating Conditions”表格查得,并转换为T113-S3寄存器要求的编码格式。例如,tRCD=13.5ns,在T113-S3中需写入DDR_TIMING_CFG1[15:8],其编码公式为(tRCD * 1000 / CLK_PERIOD) - 1,假设主频为400MHz(CLK_PERIOD=2.5ns),则计算值为(13.5*1000/2.5)-1 = 5399,再转换为16进制填入寄存器。SPL成功后,会将完整的U-Boot主镜像从SD卡拷贝到已初始化好的DDR中运行。
第三阶段:U-Boot主程序——“指挥官”,协调外设与内核交接
此时U-Boot运行在DDR中,功能完整。它要完成:
- 初始化UART、I2C、SPI等基础外设(确保串口能打印log);
- 解析设备树(Device Tree Blob, DTB),将其加载到内存指定位置;
- 加载Linux内核镜像(zImage或Image)到内存;
- 设置启动参数(bootargs),如
console=ttyS0,115200n8 root=/dev/mmcblk0p2 rw; - 最终通过
bootz或booti命令跳转到内核入口。这里有个极易忽略的陷阱:T113-S3的U-Boot默认配置中,CONFIG_SYS_TEXT_BASE(U-Boot链接基地址)常设为0x4a000000,但这与内核期望的加载地址(通常是0x40008000)冲突。若不修改U-Boot配置并重新编译,内核镜像会被覆盖,导致启动失败。解决方案是在U-Boot配置文件(如configs/t113-s3_defconfig)中添加CONFIG_SYS_TEXT_BASE=0x40008000,并确保CONFIG_SYS_LOAD_ADDR也同步调整。
第四阶段:Linux Kernel——“操作系统大脑”,接管硬件资源
内核启动后,首先执行汇编层的head.S,完成CPU模式切换、MMU初始化;接着进入C语言start_kernel(),依次调用setup_arch()(解析DTB)、paging_init()(建立页表)、rest_init()(创建init进程)。此时,内核会读取DTB中/chosen节点下的bootargs属性,并据此挂载根文件系统。如果root=参数指向的设备不存在(如/dev/mmcblk0p2但eMMC分区表损坏),内核会panic并打印VFS: Unable to mount root fs on unknown-block(179,2)。这并非内核bug,而是根文件系统定位失败的明确信号。
2.2 关键硬件接口与调试通道的物理确认
在动手写代码前,必须用万用表和示波器“触摸”你的硬件。T113-S3开发中最常失效的三个物理接口,我称之为“三座大山”:
第一座:UART0(调试串口)——你的“生命线”
T113-S3的UART0(对应管脚PA0/PA1)是BootROM和U-Boot默认的调试输出通道。但很多客户原理图设计时,为了节省PCB空间,将PA0/PA1接到一个非标准电平的USB转串口芯片(如CH340G),而CH340G的TXD引脚是3.3V CMOS电平,与T113-S3的UART_RX(PA0)完美匹配;但CH340G的RXD引脚是5V TTL电平,直接接到T113-S3的UART_TX(PA1)会导致PA1引脚电压被拉高至4.5V以上,超出其绝对最大额定值(-0.5V ~ 3.6V),轻则通信不稳定,重则永久损坏IO。实测方案:在PA1与CH340G的RXD之间串联一个1KΩ限流电阻,并用万用表直流电压档测量PA1对地电压,正常应稳定在0~3.3V之间。若上电后PA1电压异常,立即断电检查。
第二座:eMMC接口——“硬盘”的可靠性基石
T113-S3支持eMMC 4.51协议,其时钟线(eMMC_CLK)对布线长度和阻抗控制极为敏感。官方参考设计要求eMMC_CLK走线长度误差不超过±5mm,且必须包地处理。我曾调试一块客户板子,eMMC能被U-Boot识别(mmc info命令返回信息),但内核启动后频繁报end_request: I/O error, dev mmcblk0, sector 0。用示波器抓CLK波形,发现上升沿存在严重过冲(Overshoot)和振铃(Ringing),幅度达1.2Vpp。根源是CLK走线未包地,且末端未加22Ω串联电阻进行阻抗匹配。解决方案:在eMMC_CLK信号源端(即T113-S3的eMMC_CLK引脚附近)焊接一颗22Ω贴片电阻,再连接到eMMC芯片。此操作后,波形恢复干净方波,错误消失。
第三座:电源管理单元(PMU)——“能源管家”的静默故障
T113-S3依赖外部PMU芯片(如AXP223)提供多路稳压电源(VDD-CPU、VDD-GPU、VDD-IO等)。PMU通过I2C与SoC通信,其寄存器配置决定了各路电源的开启时序和电压值。若PMU的I2C地址配置错误(如SDK中默认为0x34,但客户用了0x35),U-Boot的axp223_init()函数会因I2C通信失败而跳过电源初始化,导致CPU核心电压不足,内核虽能启动,但运行几秒后随机死机。排查方法:在U-Boot源码drivers/power/axp223.c中,于axp223_init()函数开头添加printf("AXP223 probing at 0x%x\n", AXP223_I2C_ADDR);,编译后观察串口log是否打印该地址。若无打印,则说明I2C通信根本未建立,需检查I2C总线硬件连接(上拉电阻是否焊接、线路是否短路)。
3. U-Boot移植实战:从零构建T113-S3专属引导程序
3.1 获取与裁剪官方U-Boot源码的精准操作步骤
全志官方提供的U-Boot源码(通常位于SDK的u-boot-2018.07目录下)是一个“瑞士军刀”,功能全但体积臃肿。直接编译会生成超过1MB的镜像,远超BootROM能加载的容量上限(通常为512KB)。因此,裁剪是必须的第一步,而非可选项。
第一步:锁定基础配置文件
进入U-Boot源码根目录,执行:
make distclean make t113-s3_defconfigt113-s3_defconfig是全志为该芯片定制的基础配置,它已禁用大量无关功能(如USB Host、PCIe、SATA),但仍有优化空间。关键是要理解这个配置文件的生成逻辑:它由scripts/kconfig/conf工具根据arch/arm/configs/t113-s3_defconfig文本文件生成.config。因此,所有后续裁剪都应在该文本文件中进行,而非在图形界面(make menuconfig)中修改,以确保可复现性。
第二步:针对性裁剪三大冗余模块
打开arch/arm/configs/t113-s3_defconfig,用vim或nano编辑,重点修改以下三处:
- 禁用所有网络协议栈:删除或注释掉所有以
CONFIG_NET、CONFIG_CMD_NET、CONFIG_CMD_DHCP开头的行。T113-S3的U-Boot仅需串口调试和eMMC加载,无需网络功能。此举可减少约120KB代码体积。 - 禁用图形显示支持:删除所有
CONFIG_VIDEO、CONFIG_LCD、CONFIG_SPLASH_SCREEN相关配置。即使你的板子有LCD屏,U-Boot阶段也不需要显示,内核启动后再由Framebuffer驱动接管。此项节省约80KB。 - 精简命令集:保留最核心的
CONFIG_CMD_BOOTZ、CONFIG_CMD_MMC、CONFIG_CMD_FAT、CONFIG_CMD_GPIO、CONFIG_CMD_I2C,其余如CONFIG_CMD_USB、CONFIG_CMD_SF(SPI Flash)全部删除。一个精简后的U-Boot命令集应控制在20个以内,体积可再降100KB。
第三步:验证裁剪效果与编译
执行make menuconfig,进入图形界面,按/键搜索CONFIG_SYS_TEXT_BASE,确认其值为0x40008000(与内核加载地址对齐)。然后编译:
make -j$(nproc)编译完成后,检查生成的u-boot.bin大小:ls -lh u-boot.bin。理想尺寸应在380KB~420KB之间。若大于450KB,说明裁剪不彻底,需回到第二步复查。若小于350KB,需警惕是否误删了关键功能(如CONFIG_CMD_MMC),导致eMMC无法识别。
3.2 DDR初始化参数的“手把手”配置指南
T113-S3的DDR初始化是移植成败的分水岭。官方SDK中的board/sunxi/t113-s3/dram_t113.c文件包含了针对主流LPDDR3颗粒的初始化序列,但客户自选的颗粒型号不同,参数必须重算。
第一步:获取你的LPDDR3颗粒Datasheet
以常见的三星K4E6E304EC为例,下载其PDF文档,定位到“AC Timing Parameters”表格。找到以下关键参数(单位:纳秒ns):
tRCD:RAS to CAS Delay = 13.5nstRP:Row Precharge Time = 13.5nstRAS:Active to Precharge Delay = 32nstRFC:Refresh Cycle Time = 160ns
第二步:计算T113-S3寄存器编码值
T113-S3的DDR控制器时钟(DDR_CLK)频率由PLL生成,通常为400MHz(周期2.5ns)。使用公式:Register_Value = (Parameter_ns * 1000 / CLK_Period_ps) - 1。
tRCD:(13.5 * 1000 / 2500) - 1 = 4.4 - 1 = 3.4→ 取整为3(寄存器位宽有限,向下取整)tRP: 同理,3tRAS:(32 * 1000 / 2500) - 1 = 12.8 - 1 = 11.8→11tRFC:(160 * 1000 / 2500) - 1 = 64 - 1 = 63
第三步:修改U-Boot源码中的DDR配置结构体
打开board/sunxi/t113-s3/dram_t113.c,找到struct dram_para结构体实例(通常名为dram_para)。修改其成员:
.dram_tpr0 = (11 << 24) | (3 << 16) | (3 << 8) | (63 << 0), // tRAS, tRCD, tRP, tRFC注意:dram_tpr0寄存器的bit分配是固定的,必须严格按照[31:24] tRAS, [23:16] tRCD, [15:8] tRP, [7:0] tRFC的顺序填入计算值。填错一位,DDR初始化必败。
第四步:烧写与验证
将编译好的u-boot.bin通过sunxi-fel工具烧写到SD卡:
sudo sunxi-fel -p spiflash-write 0 u-boot.bin上电后,若串口打印出DRAM: 512 MiB,说明DDR初始化成功。若打印DRAM: 0 MiB或无任何输出,则参数计算或寄存器填入有误,需逐项复查。
3.3 设备树(DTS)的定制化编写与编译
设备树是Linux内核与硬件之间的“契约”,T113-S3的DTS文件(如arch/arm/boot/dts/sun50i-t113-s3.dts)必须与你的硬件设计100%一致。
第一步:创建你的板级DTS文件
复制官方参考文件:
cp arch/arm/boot/dts/sun50i-t113-s3.dts arch/arm/boot/dts/sun50i-t113-s3-myboard.dts并在Makefile中添加编译规则:dtb-$(CONFIG_ARCH_SUNXI) += sun50i-t113-s3-myboard.dtb。
第二步:精准修改关键节点
- CPU节点:确认
cpu@0和cpu@1的enable-method为"psci",operating-points-v2引用正确的opp-table。 - Memory节点:
reg属性必须与你实际的DDR容量和起始地址匹配,如reg = <0x40000000 0x20000000>表示512MB内存从0x40000000开始。 - Serial节点:
&uart0节点下,status = "okay";,pinctrl-0 = <&uart0_pins_a>;,确保引脚复用配置正确。 - eMMC节点:
&emmc0下,bus-width = <8>;(8位总线),non-removable;(固定安装),vmmc-supply = <®_vcc3v3>;(电源供应引用)。
第三步:编译与烧写DTB
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sun50i-t113-s3-myboard.dtb生成的sun50i-t113-s3-myboard.dtb需与内核镜像一同烧写到eMMC的boot分区。
4. Linux内核移植与启动调试:从“黑屏”到“/ #”的破壁之旅
4.1 内核配置的最小化与国产化适配
T113-S3的Linux内核(推荐使用Linux 5.10 LTS)配置,核心原则是“够用即止”,避免引入不必要的驱动和子系统。
第一步:启用T113-S3专属配置
执行make ARCH=arm menuconfig,进入图形界面,确保以下选项被选中:
System Type→Allwinner SoCs support→Allwinner T113-S3 SoC support(必须勾选)Device Drivers→Character devices→Sunxi System Control Module (SCM) support(用于访问安全寄存器)Device Drivers→Input device support→Keyboards→Allwinner A10/A20/A33/A83T/T113-S3/S3 RSB keyboard support(若使用RSB接口键盘)
第二步:禁用高风险驱动
- 禁用GPU驱动:
Device Drivers→Graphics support→Allwinner sunxi DRM support→ 取消勾选。T113-S3的Mali-400 MP2驱动在主线内核中尚不完善,强行启用会导致内核panic。图形需求留待用户空间(如Qt)通过Framebuffer实现。 - 禁用USB OTG Gadget:
Device Drivers→USB support→USB Gadget Support→ 取消勾选。该功能在T113-S3上稳定性差,易引发USB PHY复位。 - 禁用音频驱动:
Device Drivers→Sound card support→Advanced Linux Sound Architecture→ 取消勾选。音频功能可通过ALSA用户库在应用层实现,内核层暂不启用。
第三步:配置根文件系统挂载方式
在Boot options→Default kernel command string中,输入:console=ttyS0,115200n8 earlyprintk loglevel=8 root=/dev/mmcblk0p2 rw rootwait
其中rootwait至关重要,它告诉内核等待eMMC设备完全就绪后再尝试挂载,避免因eMMC初始化慢于内核启动而导致VFS: Cannot open root device错误。
4.2 内核启动日志的逐行解读与故障定位
当串口出现内核log时,不要急于滚动屏幕,而是逐行分析。以下是典型成功启动log的关键节点及对应含义:
[ 0.000000] Booting Linux on physical CPU 0x0 [ 0.000000] Linux version 5.10.113 (user@host) (arm-linux-gnueabihf-gcc (GCC) 10.2.0, GNU ld (GNU Binutils) 2.35.2) #1 SMP PREEMPT Thu May 16 10:23:45 CST 2024 [ 0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c5387d [ 0.000000] OF: fdt: Machine model: Allwinner T113-S3 Evaluation Board这三行表明:CPU被正确识别(ARMv7 Cortex-A7),设备树(fdt)被成功解析,机器模型名(
model属性)与DTS中/ { model = "Allwinner T113-S3 Evaluation Board"; };完全一致。若此处显示Unknown machine,说明DTB未被正确加载或损坏。
[ 0.000000] Memory: 499120K/524288K available (10240K kernel code, 720K rwdata, 3200K rodata, 1024K init, 256K bss, 25168K reserved, 0K cma-reserved)此行确认内存总量(524288K = 512MB)和可用内存(499120K ≈ 487MB)均正常。若数字远小于512MB(如只有128MB),说明DDR初始化失败或内存区域被错误保留。
[ 0.000000] random: get_random_bytes called from start_kernel+0x31c/0x520 with crng_init=0 [ 0.000000] percpu: Embedded 21 pages/cpu s52224 r8192 d22528 u86016 [ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 126976 [ 0.000000] Kernel command line: console=ttyS0,115200n8 earlyprintk loglevel=8 root=/dev/mmcblk0p2 rw rootwait
Kernel command line必须与你在menuconfig中配置的完全一致。若此处显示root=/dev/ram0或其他错误路径,说明U-Boot传递的bootargs有误,需检查U-Boot环境变量bootargs的设置。
[ 1.234567] mmc0: new high speed MMC card at address 0001 [ 1.234568] mmcblk0: mmc0:0001 QEMU01 3.69 GiB [ 1.234569] mmcblk0: p1 p2这是eMMC被内核成功识别的关键标志。
p1 p2表示分区表被正确读取,其中p2即为根文件系统所在分区。若此处无p1 p2输出,或报错mmc0: error -110 whilst initialising SD card,说明eMMC硬件或驱动有问题。
[ 2.345678] VFS: Mounted root (ext4 filesystem) readonly on device 179:2. [ 2.345679] devtmpfs: mounted [ 2.345680] Freeing unused kernel memory: 1024K [ 2.345681] Run /sbin/init as init process
Mounted root表示根文件系统挂载成功。Run /sbin/init是内核启动用户空间的第一个信号。若在此之后卡住,问题一定出在RootFS或init进程本身。
4.3 根文件系统(RootFS)的构建与部署
一个最小化的T113-S3 RootFS,核心是BusyBox,而非庞大的Debian或Ubuntu。
第一步:构建BusyBox
下载BusyBox源码,执行:
make menuconfig # 在Settings中,勾选"Build BusyBox as a static binary" # 在Applets中,只选你需要的命令:ash, ls, cp, mv, mkdir, mount, umount, ifconfig, ping, etc. make -j$(nproc) make installmake install会生成_install目录,其中包含所有二进制文件。
第二步:构建最小RootFS骨架
mkdir -p rootfs/{bin,sbin,etc,proc,sys,dev,tmp,root,usr/{bin,sbin,lib},lib,lib/modules} cp -a _install/* rootfs/ # 复制必要的库文件(从交叉编译工具链中) arm-linux-gnueabihf-gcc -print-sysroot # 获取sysroot路径 cp -a /path/to/sysroot/lib/{libc.so.6,ld-linux-armhf.so.3} rootfs/lib/ # 创建设备节点 sudo mknod -m 600 rootfs/dev/console c 5 1 sudo mknod -m 600 rootfs/dev/null c 1 3第三步:制作eMMC镜像并烧写
# 创建ext4文件系统镜像 dd if=/dev/zero of=rootfs.img bs=1M count=256 mkfs.ext4 -F rootfs.img # 挂载并拷贝文件 sudo mkdir /mnt/rootfs sudo mount -o loop rootfs.img /mnt/rootfs sudo cp -a rootfs/* /mnt/rootfs/ sudo umount /mnt/rootfs # 使用sunxi-fel烧写到eMMC的第二个分区(p2) sudo sunxi-fel -p write 0x40000000 rootfs.img sudo sunxi-fel -p write 0x40000000 rootfs.img 0x40000000注意:write命令的第三个参数是eMMC的起始扇区号,需根据你的分区表计算。通常p1(boot分区)占2MB(4096扇区),p2从扇区4096开始。
5. 常见问题与硬核排查技巧实录:那些让工程师彻夜难眠的“幽灵Bug”
5.1 串口无任何输出——从“死寂”到“听见心跳”的全流程诊断
这是移植初期最令人绝望的问题。请按以下顺序,用排除法逐一验证:
| 检查项 | 操作方法 | 预期结果 | 失败含义 |
|---|---|---|---|
| BootROM是否运行 | 用示波器测量UART0的TXD(PA0)引脚对地电压 | 上电瞬间应有短暂(<100ms)的3.3V脉冲 | BootROM未启动,检查供电、复位电路、晶振 |
| U-Boot SPL是否运行 | 断开U-Boot主程序,仅烧写SPL(u-boot-spl.bin),用示波器抓PA0波形 | 应看到一串规律的方波(SPL的调试输出) | SPL未运行,检查SPL烧写位置、BootROM启动介质识别 |
| U-Boot主程序是否加载 | 将U-Boot编译为u-boot.elf,用JTAG调试器(如J-Link)连接,设置断点在_start | JTAG能停在_start,且寄存器r0为0x40008000 | U-Boot未被BootROM正确加载,检查启动头格式、SD卡格式 |
| 串口驱动是否初始化 | 在U-Boot源码drivers/serial/serial_sunxi.c的sunxi_serial_init()函数开头添加puts("UART init OK\n"); | 串口打印该字符串 | UART驱动未初始化,检查CONFIG_SYS_NS16550_COM1配置、引脚复用 |
提示:若示波器看到PA0有杂乱无章的毛刺,而非清晰方波,大概率是电源噪声过大或地线接触不良。在T113-S3的VDD-IO电源引脚附近,用烙铁焊一颗10uF钽电容到地,能立竿见影改善。
5.2 内核卡在“Starting kernel ...”——启动链路断裂的终极定位
U-Boot打印Starting kernel ...后,串口彻底静音,这是最典型的“内核未启动”现象。原因几乎总是内存地址冲突或设备树错误。
硬核排查法:用U-Boot的md.b命令内存探测
在U-Boot命令行下,执行:
# 查看内核镜像zImage是否被正确加载到0x40008000 md.b 0x40008000 20 # 应看到类似:40008000: 01 6f 28 18 00 00 00 00 00 00 00 00 00 00 00 00 .o(............. # 前4字节`01 6f 28 18`是ARM zImage的魔数,证明加载正确 # 查看设备树DTB是否被加载到0x41000000(U-Boot默认DTB加载地址) md.b 0x41000000 20 # 应看到:41000000: d0 0d fe ed 00 00 00 00 00 00 00 00 00 00 00 00 ................ # 手动执行内核启动,强制指定地址 bootz 0x40008000 - 0x41000000若bootz命令后仍无反应,说明内核镜像或DTB损坏。此时,用cmp命令对比烧写前后的文件MD5:
md5sum u-boot.bin # 烧写前 # 然后用sunxi-fel读回:sudo sunxi-fel read 0x00000000 0x100000 uboot_read.bin md5sum uboot_read.bin # 烧