linux系统启动失败之flash异常分析

1,当系统起不来,出现flash ECC error怎么定位是哪里的问题呢

思路:读出单板上的flash数据和烧写到单板上的bin文件进行对比。

(1)系统可以正常系统,可以进uboot

  • sf read / sf write:用于操作SPI Flash。

U-Boot大小为512KB(0x80000),存储在Flash的起始位置。

U-Boot读取命令

复制代码
    # sf read <内存地址> <Flash偏移> <读取大小>
    sf read 0x81000000 0x0 0x80000
    ```

*   `0x81000000`:数据加载到内存的地址。
*   `0x0`:从Flash的0地址开始读。
*   `0x80000`:读取512KB。
  • 导出到Windows

    复制代码
      tftp 0x81000000 u-boot.bin 0x80000
      ```
    • 执行后,Windows上会得到一个 u-boot.bin 文件。
  • nand read / nand write:用于操作NAND Flash。

读取整个NAND Flash数据

NAND Flash的一个关键特性是坏块 。U-Boot的nand read命令非常智能,它会自动跳过坏块,只读取有效数据。

  • 场景:假设单板有一个256MB的NAND Flash。

  • 计算

    • 总字节数:256MB = 0x10000000 字节。
  • 注意 :虽然物理容量是256MB,但由于坏块的存在,实际读出的有效数据量可能会略小。nand read会处理这一切。

  • U-Boot读取命令(读取整个芯片)

    复制代码
      # nand read <内存地址> <Flash偏移> <读取大小>
      nand read 0x81000000 0x0 0x10000000
      ```
    • 0x81000000:数据加载到内存的地址。
    • 0x0:从NAND Flash的0地址开始读。
    • 0x10000000:尝试读取256MB的数据(命令会自动跳过坏块)。
  • 导出到Windows

    复制代码
      # ${filesize} 是U-Boot变量,在上次read后自动设置为实际读取的字节数
      tftp 0x81000000 full_nand_dump.bin ${filesize}
      ```

    使用 ${filesize} 变量可以确保只传输实际读取到的数据长度。


四、具体举例:读取并导出不同组件

假设我们使用的内存加载地址统一为 0x81000000,并且分区布局如下:

  • U-Boot: 存储在NAND Flash最前端,大小1MB。
  • Kernel: 紧随U-Boot,从1MB偏移开始,大小5MB。
  • Device Tree: 紧随Kernel,从6MB偏移开始,大小64KB。

1. 读取并导出 U-Boot (u-boot.bin)

  • U-Boot读取命令

    复制代码
      nand read 0x81000000 0x0 0x100000
      ```
    • 0x0:从NAND的0地址开始读。
    • 0x100000:读取1MB。
  • 导出到Windows

    复制代码
      tftp 0x81000000 u-boot.bin 0x100000
      ```
  • 分析 :对比这个u-boot.bin和你电脑上原始的、正确的u-boot.bin文件。如果文件开头是0xFF或与原始文件不一致,说明U-Boot损坏或其所在的块变成了坏块,这是单板无法启动的最常见原因。

2. 读取并导出 Linux内核 (kernel.bin)

  • U-Boot读取命令

    复制代码
      nand read 0x81000000 0x100000 0x500000
      ```
    • 0x100000:跳过前1MB(留给U-Boot)。
    • 0x500000:读取5MB的内核数据。
  • 导出到Windows

    复制代码
      tftp 0x81000000 kernel.bin 0x500000
      ```
  • 分析 :对比kernel.bin。如果损坏,U-Boot可能能启动并打印信息,但在加载内核时会失败、卡死或报错 "Kernel panic - not syncing"。

3. 读取并导出 设备树 (dts.bin)

  • U-Boot读取命令

    复制代码
      nand read 0x81000000 0x600000 0x10000
      ```
    • 0x600000:从6MB偏移开始读。
    • 0x10000:读取64KB的设备树数据。
  • 导出到Windows

    复制代码
      tftp 0x81000000 dts.bin 0x10000
      ```
  • mmc read / mmc write:用于操作eMMC或SD卡

通用导出方法(以TFTP为例)

这是最常用、速度最快的方法。

  1. Windows端准备

    • 下载并运行一个TFTP服务器软件,如 tftpd64
    • 将其工作目录设置为你想保存文件的目录(例如 D:\Backup)。
    • 记住你Windows电脑的IP地址,例如 192.168.1.100
  2. U-Boot端设置网络

    复制代码
     # 设置单板的IP地址
     setenv ipaddr 192.168.1.10
     # 设置TFTP服务器(你的Windows电脑)的IP地址
     setenv serverip 192.168.1.100
     # 保存环境变量(可选,但推荐)
     saveenv
     ```
  3. U-Boot端导出命令

    复制代码
     # tftp <内存地址> <要保存的文件名> <文件大小>
     tftp 0x81000000 backup.bin 0x80000
     ```

    执行后,你会在 tftpd64 的窗口看到传输进度,完成后 D:\Backup 目录下就会出现 backup.bin


三、读取整个eMMC数据

要读取整个eMMC,你需要知道它的总容量,并将其转换为块数。eMMC的默认块大小是512字节(0x200)

  • 场景:假设单板有一个8GB的eMMC。

  • 计算

    • 总字节数:8GB = 8 1024 1024 * 1024 = 0x200000000 字节。
    • 总块数:0x200000000 / 0x200 = 0x10000000 块。
  • 注意:8GB的数据量巨大,你的单板RAM可能没有这么大空间来一次性存储。更实际的做法是读取启动相关的关键部分(例如前几百MB)。这里我们以读取前512MB为例。

  • U-Boot读取命令(读取前512MB)

    复制代码
      # mmc read <内存地址> <起始块号> <块数>
      # 起始块号: 0
      # 块数: 512MB / 512字节 = 0x100000
      mmc read 0x81000000 0x0 0x100000
      ```
    • 0x81000000:数据加载到内存的地址。
    • 0x0:从eMMC的第0块开始读。
    • 0x100000:读取 0x100000 个块(即512MB)。
  • 导出到Windows

    复制代码
      tftp 0x81000000 full_emmc_512MB.bin 0x20000000
      ```
    • 0x20000000 是512MB的字节数。

四、具体举例:读取并导出不同组件

假设我们使用的内存加载地址统一为 0x81000000,并且分区布局如下:

  • U-Boot: 存储在eMMC最前端,大小1MB。
  • Kernel: 紧随U-Boot,从1MB偏移开始,大小5MB。
  • Device Tree: 紧随Kernel,从6MB偏移开始,大小64KB。

1. 读取并导出 U-Boot (u-boot.bin)

  • 计算

    • 起始块号:0x0 / 0x200 = 0x0
    • 块数:1MB / 0x200 = 0x100000 / 0x200 = 0x800
  • U-Boot读取命令

    复制代码
      mmc read 0x81000000 0x0 0x800
      ```
  • 导出到Windows

    复制代码
      tftp 0x81000000 u-boot.bin 0x100000
      ```
  • 分析 :对比这个u-boot.bin和你电脑上原始的、正确的u-boot.bin文件。如果文件开头是0xFF或与原始文件不一致,说明U-Boot损坏,这是单板无法启动的最常见原因。

2. 读取并导出 Linux内核 (kernel.bin)

  • 计算

    • 起始块号:1MB / 0x200 = 0x100000 / 0x200 = 0x800
    • 块数:5MB / 0x200 = 0x500000 / 0x200 = 0x2800
  • U-Boot读取命令

    复制代码
      mmc read 0x81000000 0x800 0x2800
      ```
  • 导出到Windows

    复制代码
      tftp 0x81000000 kernel.bin 0x500000
      ```
  • 分析 :对比kernel.bin。如果损坏,U-Boot可能能启动并打印信息,但在加载内核时会失败、卡死或报错 "Kernel panic - not syncing"。

3. 读取并导出 设备树 (dts.bin)

  • 计算

    • 起始块号:6MB / 0x200 = 0x600000 / 0x200 = 0x3000
    • 块数:64KB / 0x200 = 0x10000 / 0x200 = 0x80
  • U-Boot读取命令

    复制代码
      mmc read 0x81000000 0x3000 0x80
      ```
  • 导出到Windows

    复制代码
      tftp 0x81000000 dts.bin 0x10000
      ```
  • 分析 :对比dts.bin。如果设备树损坏,内核可能在启动初期(通常在 "Starting kernel ..." 之后)无法识别硬件(如内存、串口),导致没有任何输出或直接卡

(2) linux系统启动正常后

  • Linux系统工具 (如果Flash能被Linux识别):
    • dd:可以直接从块设备(如/dev/mmcblk0)读取原始数据。
    • nanddump:用于读取MTD分区(NAND Flash)的原始数据。

(2)系统异常不能启动

  • J-Link / J-Flash:功能强大,支持芯片种类最多,商业软件,但非常稳定可靠。
  • OpenOCD:开源免费,完全通过命令行操作,非常灵活,适合集成到自动化脚本中。配合GDB可以进行调试。是J-Link的绝佳替代品。

nor flash分析

连接与配置

  1. 连接硬件 :将J-Link的SWD引脚(VTREF, GND, SWDIO, SWCLK)连接到单板。
  2. 打开J-Flash:创建新项目,选择对应的CPU内核(如Cortex-A7)。

读取NOR Flash数据

NOR Flash的读取非常直接,因为它就像一块只读内存。

  1. 连接目标 :点击 Target -> Connect
  2. 执行读取 :点击 Target -> Read back -> Range...
    • 为什么选"Range"? 因为NOR Flash是内存映射的,我们直接从它的映射地址读取即可。
  3. 设置地址范围
    • Start address : 0x60000000 (SPI NOR Flash的起始地址)
    • End address : 0x60000000 + 0x1000000 - 1 (即 0x60FFFFFF,读取全部16MB)
  4. 保存数据 :读取完成后,将数据保存为 readback_from_nor.bin

nand flash分析

  1. 连接目标 :点击 Target -> Connect
  2. 执行读取 :点击 Target -> Read back -> Entire Chip
    • 为什么选"Entire Chip"? 对于NAND Flash,这个选项会指示J-Link通过SoC的NAND控制器去读取整个芯片。在读取过程中,它会自动跳过工厂坏块和运行中产生的坏块,并将每个页的有效数据(不包括OOB区域)拼接起来,形成一个连续的bin文件。这正是我们想要的"逻辑上"的完整镜像。
  3. 保存数据 :读取完成后,将数据保存为 readback_from_nand.bin

emmc分析

一,使用RKDevTool读取eMMC数据并对比

二,使用J-Link/J-Flash读取eMMC

1. 硬件连接

将J-Link的JTAG引脚(如TDI、TDO、TMS、TCK、GND、VTREF)正确连接到单板的JTAG接口。

2. 打开J-Flash

  1. 启动J-Flash,创建新项目。
  2. 选择正确的CPU内核(如Cortex-A7、Cortex-A55等)。

3. 连接目标

  • 点击Target -> Connect
  • 若连接成功,右下角会显示连接状态。

4. 设置读取范围

  • 点击Target -> Read back -> Range...
  • 设置地址范围:
    • Start address0x14000000(eMMC起始地址)。
    • End address0x14000000 + 0x1000000 - 1(即0x13FFFFFF,读取全部16MB)。

5. 执行读取

  • 点击OK,J-Link将通过SoC的eMMC控制器读取数据。
  • 等待读取完成(可能需要几分钟)。

6. 保存数据

  • 读取完成后,点击File -> Save Data As...,保存为readback.bin

读取数据后,使用beyond compare工具将烧写的软件包和读出来的bin文件进行对比分析。

编程器读取flash/emmc数据

RT809H编程器

1. 适用场景

  • 芯片类型:支持SPI NOR/NAND Flash、eMMC、MCU内置Flash等。
  • 封装:BGA、TSOP、SOP等,支持免拆焊飞线读取。
  • 典型应用:电视主板eMMC修复、路由器NAND Flash读取、工业设备固件提取。

2. 操作步骤

(1)硬件连接

  • 拆焊法:拆下芯片后放入专用转接座(如BGA转接板)。
  • 飞线法:焊接5根线(CLK、CMD、D0、VCC、GND)到芯片引脚,无需拆焊。
  • 测试夹法:使用SOP8/SOP16测试夹(需配合RT809H专用夹具)。

(2)软件操作

  1. 智能识别
    • 打开RT809H软件,点击"智能识别",自动检测芯片型号。
    • 若识别失败,手动输入芯片型号(如"EMMCAUTOISP")。
  2. 读取数据
    • 点击"读取",选择保存路径(如emmc_dump.bin)。
    • 支持分区读取(如Bootloader、用户数据区)。
  3. 高级功能
    • 坏块管理:自动跳过坏块,修复ECC校验错误。
    • 脱机烧录:支持批量烧录,无需连接电脑。

(3)实际案例

  • eMMC引导修复
    焊接飞线后读取eMMC,擦除坏块后重新写入固件,解决设备无法启动问题。

TNM5000编程器

相关推荐
电鱼智能的电小鱼1 天前
基于电鱼 ARM 工控机的井下AI故障诊断方案——让煤矿远程监控更智能、更精准
网络·arm开发·人工智能·算法·边缘计算
GilgameshJSS2 天前
STM32H743-ARM例程35-DHCP
c语言·arm开发·stm32·单片机·嵌入式硬件
GilgameshJSS2 天前
STM32H743-ARM例程34-BootROM
c语言·arm开发·stm32·单片机·嵌入式硬件
robin8611092 天前
Keil(MDK-ARM)和 STM32CubeIDE对比
arm开发·stm32·嵌入式硬件
学习和思考2 天前
为什么我的vscode有的时候可以跳转,有的时候不能跳转
arm开发·ide·驱动开发·vscode·学习·1024程序员节
sunshine~~~3 天前
【笔记】macOs arm架构安装虚拟机Ubuntu环境:ROS2 + Python开发
arm开发·笔记·python·macos·ros2
碧海银沙音频科技研究院3 天前
i2s封装成自己定义8路音频数据发送方法
arm开发·人工智能·深度学习·算法·音视频
IAR Systems3 天前
使用J-Link Attach NXP S32K3导致对应RAM区域被初始化成0xDEADBEEF
arm开发·数据库·嵌入式软件开发·iar
chen36733 天前
嵌入式AI Arm_linux_第一个Demo_让IPU跑起来
linux·arm开发·人工智能