分区错位 · 坏块跳过不一致 · NAND 类器件量产排查手册
编制日期 2026-09-21 | 版本号 Rev 1.0
XTX 芯天下 · FAE 现场技术文档 | 面向 SPI NAND / PPI NAND(并行 NAND)/ SD NAND / eMMC 裸片量产烧录 | 2026-09 版
分区布局、坏块表位置、ECC 强度与算法以具体平台驱动代码与器件 datasheet 为准;本文仅展示机制。
- 本文出现的所有地址、偏移、块号、字节数、ECC 纠正能力均为说明机制的示例,动手前必须逐项与器件 datasheet 和目标平台驱动代码核对,不得直接照抄。
- NAND 类器件(SPI NAND / PPI NAND / SD NAND / eMMC)出厂自带坏块是行业常态,出厂坏块上限与标记方式以 datasheet 为准;发现坏块不等于来料不良,本文不讨论坏块本身,只讨论「两侧对坏块的理解不一致」。
- 整片擦除、重烧、坏块表重建三类操作会永久破坏现场数据,执行前必须先完成坏块信息导出与镜像留证(见第 12.4 节)。
- 平台相关术语(UBI / PEB / LEB、MBR / GPT、BBT、OOB、spare、BCH)在不同 SDK 中命名与含义并不统一,以所用 SDK 源码与文档为准。
- 同一现象在不同平台可能落到不同类目,本文给的是排查顺序与判据,不是结论清单。
一句话结论:「烧录通过但系统找不到数据 / 文件系统挂不上」几乎从不意味着芯片坏了。
它的本质是烧录器的裸片视角(烧什么地址 → 写什么内容)与系统驱动的运行视角
(哪个逻辑块号 → 哪个物理块号、ECC 由谁算)没有完全对齐。
烧录器的 Verify PASS 只证明「你让它写的字节,它读回来是一样的」——它既不认识你的分区表,
也不认识驱动里的 BBT 和 ECC 布局。
这份文档解决什么
解决的是 NAND 类器件(SPI NAND、PPI NAND、SD NAND、eMMC)在量产裸片烧录阶段, 校验 100% 通过、装板后却「找不到数据」或「文件系统挂不上」这一类问题的定位与根治方法。 全文把问题拆成三层、七个类目,每一类都按「机制 → 判据 → 立即动作 → 根治动作」四段给出。 第 10 章是可直接翻查的速查表,第 11 章是可带进车间的四方联合确认 SOP,第 12 章是可复制的清单与模板。
需要说清楚的是:本文档讨论的不是「坏块本身」,而是「两侧对坏块与分区的理解不一致」。 NAND 出厂自带坏块是行业常态,不是来料质量问题;把坏块当成故障去换料,只会让真正的不一致继续留在产线上。
怎么用这份文档
- 先用可观测现象定层:能不能读到卷头 / Superblock、报不报 ECC 错误,据此落到第 2 章的三层之一,不要一上来就换芯片。
- 在层内定位类目:第 3~9 章每章一类,每章开头都有「判据」,用判据筛掉不符合的类目,而不是逐个试。
- 一次只改一个变量:分区偏移、坏块策略、ECC 配置每次只动一处,改完全片重烧、装板实跑,禁止叠加修改。
- 两侧各导出一份证据再比对:烧录器侧的分区表与坏块清单、驱动侧的分区表与坏块清单,逐行 diff,不要靠记忆判断。
- 用装板实跑闭环:任何配置变更,最终判定以「首件装板跑通 + 断电重启通过 + 抽检与首件一致」为准。
1. 问题本质:两套视角的不一致
分区错位与坏块跳过不一致,通常不是两个独立故障,而是同一件事的两个出口: 烧录器对这片介质的理解,与目标系统驱动对这片介质的理解,不是同一套。 本章先把两套视角并排放出来,再讲清楚为什么这两类问题会结伴出现、以及为什么它最容易被误判成器件不良。
1.1 共同根因:烧录器看物理,驱动看逻辑
烧录器在裸片状态下工作,它拿到的是一整片连续的物理地址空间,动作是「你把镜像给我、 告诉我写到哪个地址,我就写过去,遇到坏块按配置处理」。 系统驱动在运行时工作,它拿到的是逻辑块号,动作是「上层要第 N 个逻辑块, 我去查 BBT,把它映射到某个物理块,再用硬件 ECC 引擎校验」。
这两个视角各自都自洽,但它们的接口处没有任何强制校验——烧录器不认识驱动的分区表, 驱动也不知道烧录器跳过的是哪几个块。只要两侧的配置不是同一份,错位就必然发生,而且校验 100% 通过。
1.2 逐项对照:六个维度,每一个都可能错位
把两套视角拆成六个维度逐项对照,是定位问题的起点。现场绝大多数「说不清哪里错了」的案例, 都能在这张表里找到对应的那一行。
| 维度 | 烧录器(裸片视角) | 系统驱动(运行视角) | 对不齐的后果 |
|---|---|---|---|
| 看待介质的方式 | 一整片连续物理地址空间 | 逻辑块号 LBA,需要映射 | 分区错位的源头 |
| 分区信息从哪来 | 外部导入的分区表 / 工程配置 | 设备树 / 分区定义 / MBR-GPT | 分区起点与尺寸对不上 |
| 遇到坏块怎么办 | 按工程配置跳过(或不跳) | 按 BBT 做逻辑块 → 物理块映射 | 坏块跳过不一致 |
| ECC 由谁算 | 烧录器软件算 / 或完全不算 | SoC 硬件 ECC 引擎算 | 不可纠错误刷屏 |
| OOB / spare 归谁用 | 烧录器按工程配置填 | 驱动按 spare 布局取 | 校验字节互相破坏 |
| 校验口径 | 读回字节 == 源镜像 | ECC 能过 + 卷头能找到 | 校验通过但系统挂不上 |
1.3 校验通过,到底证明了什么
这是全文最关键的一张表。烧录器的校验(Verify)本质是把写进去的内容读回来与源镜像逐字节比对, 它检验的是「数据搬运」这一件事;而系统能否找到数据、能否挂载,取决于驱动侧的「数据解释」规则。
| 校验通过能证明 | 校验通过不能证明 | 由谁决定 |
|---|---|---|
| 烧录器缓冲区里的数据与源镜像逐字节一致 | 目标系统能找到这些数据 | 驱动分区表 / 卷头位置 |
| 每个被写的页都编程成功 | 分区起点与驱动期望的一致 | 分区表是否同一份 |
| 烧录器按自己的策略处理了坏块 | 驱动按同一策略处理了同一批坏块 | 坏块标记位置 + 跳过策略 |
| 写进去的 ECC 字节与烧录配置一致 | 驱动侧算 ECC 的方式与之一致 | ECC 生成方 / 强度 / 位置 |
| 这一颗在烧录器上能跑 | 这一颗装到目标板上能跑 | 装板实跑 |
| 这一颗能跑 | 这一批 / 这个料号 / 这个批次都能跑 | 首件确认 + 装板抽检 |
1.4 为什么这两类问题总是一起出现
分区错位与坏块跳过不一致之所以高发合并出现,是因为它们之间有一条直接的因果链:
- 烧录器跳过坏块 → 被跳过的块之后,所有内容在物理上整体后移;
- 分区表的 offset 是按「没有坏块」算出来的 → 于是每个分区的物理起点都被推后了若干个块;
- 驱动不知道烧录器跳过的是哪几个块 → 它只能按自己的 BBT 与分区表重新算一遍;
- 两套算法的结果差若干个块 → 分区错位;同时逻辑块号映射到错误物理块 → 坏块跳过不一致;
- 而这个差值随每一片的坏块分布不同而不同 → 同一工程下 A 片能起来、B 片起不来。
现场最常听到的一句判断是「同一批片子有的能起有的不能起,所以是来料不良」。这个推论不成立:坏块分布逐片不同 → 跳过量逐片不同 → 物理错位量逐片不同 → 症状逐片不同,这恰恰是「两侧不一致」的典型指纹,而不是器件质量问题的指纹。
真正的证据只有一种:把能起的那片与不能起的那片各导出一份坏块清单与分区布局,逐行比对差异在哪一行。差异落在哪一行,就对应第 3~9 章的哪一类。
1.5 出厂坏块是行业常态,不是质量问题
这是本文档要纠正的第一个直觉。NAND 工艺决定了器件在出厂时就存在一定比例的坏块, datasheet 会给出出厂坏块数量上限与标记方式(具体数值与标记位置以 datasheet 为准)。 厂商在出厂前已完成标记与筛选,用户侧要做的不是「消灭坏块」,而是正确识别并一致地跳过。
- NAND 出厂时即存在一定比例坏块,属工艺常态;出厂坏块数量上限与标记方式以器件 datasheet 为准。
- 出厂坏块在出厂前已被标记(标记位置遵循器件规范),用户侧只需正确识别并跳过,不应尝试擦掉标记重用。
- 使用过程中还会产生新的坏块,由驱动在运行期识别与管理;这类坏块的处理策略属于驱动行为,必须与烧录侧的静态策略区分开看。
「烧录通过 ≠ 找得到数据」。只要现象是「校验 100% 通过但系统找不到数据或挂不上」,就不要把时间花在怀疑芯片质量上——先去对齐两侧的规则。现场统计里,器件本体不良的概率远低于配置不一致的概率。
2. 三层错位总览(决策树)
七个类目不是并列的七种故障,而是分布在三个层次上。 先定层、再定类,可以把排查路径从「七选一」缩短到「三选一,再三选一」。 本章给决策树与三层的对齐对象,后面七章每一章对应树上的一个叶子。
2.1 决策树:从现象到类目
树根是共同的现象——烧录通过,但系统找不到数据或挂不上。 往下分三条枝,分别对应三个层次;每条枝上是该层内的具体类目。 每个层面板底部有一块「判据」,先读判据:符合哪一块的判据,就进哪一层。
2.2 三层的对齐对象与拍板方
三层各自的对齐内容、配错后的暴露点、以及由谁拍板,都不一样。 这张表的用法是:先确定争议属于哪一层,再去找对应的责任方对齐, 不要跨层协商——跨层协商的典型结果是谁都觉得自己没错。
| 层 | 要对齐什么 | 配错后的暴露点 | 由谁拍板 |
|---|---|---|---|
| 分区布局层 (类 1~3) | 分区起点 offset、分区尺寸、单位、是否对齐擦除块 / PEB 边界 | 卷头 / Superblock 读不到;mount 失败;能读到数据但内容错 | 固件 + 烧录工程 (同一份分区表) |
| 坏块表层 (类 4~6) | 坏块标记位置、建表方、跳过策略、BBT 落盘位置与格式 | 逻辑块号映射到错误物理块;ECC 报错;同一片换工具结果就变 | 驱动 + 烧录工程 (同一份坏块清单) |
| ECC + spare 层 (类 7) | ECC 生成方、纠正强度、算法、字节在 spare 中的位置、覆盖范围 | uncorrectable 刷屏;空白页也报错;换片换工具症状不变 | SoC 硬件 + 驱动 (同一份 ECC 配置) |
2.3 分层的三条纪律
- 先定层,再定类。跳过分层的直接后果是在七个类目之间反复横跳,每类都改一遍, 最后连原本能跑的配置也改坏了,现场再也回不到基线。
- 每层只认一份数据源。分区布局认分区表,坏块认坏块清单,ECC 认配置项; 三份都必须版本化归档,且烧录侧与驱动侧引用的是同一个文件、同一个版本。
- 改完必须回到基线上验证。任何一层的变更都要全片重烧 + 装板实跑, 禁止在「上一次改动还没验证」的状态上继续叠加第二次改动。
现场最常见的低效排查是这样进行的:先怀疑坏块,改一次跳过策略;没好,再怀疑偏移,改一次分区表;还没好,又怀疑 ECC,改一次强度。三次改动叠加后,即使问题被碰巧解决,也没人知道是哪一次起的作用,下次换料号还会重来一遍。
正确的做法是:用第 2.1 节的判据先定层 → 在该层内用第 3~9 章的判据定类 → 只改那一处 → 全片重烧 → 装板实跑 → 通过后再归档配置快照。
3. 第 1 类:分区表错位
分区表错位是三类分区问题里最基础的一类:烧录器按 A 表写,驱动按 B 表找,而 A 与 B 不是同一份。 它有三种典型形式——起点 offset 不一致、尺寸没对齐擦除块边界、单位混用。三者可以同时存在。
3.1 机制:写在哪与找在哪不是同一张表
烧录器工作时需要的只是「镜像文件 + 起始地址」,它不会去校验这张分区表是不是驱动要用的那张。 驱动侧的分区定义来自设备树、分区表分区(MBR / GPT)或内核命令行,同样不会去问烧录器。 两边各拿各的表,只要这两份表在某个边界上差了一点点,后续所有分区的物理位置就整体错位。
3.2 三种错位形式的对照
| 错位形式 | 典型表现 | 高发原因 | 立即动作 |
|---|---|---|---|
| 分区起点 offset 不一致 | 卷头 / Superblock 在预期偏移读不到;能读到数据但内容明显错位 | 分区表版本不同;一边手工改过;单位不同导致换算偏差 | 两侧各导出一份分区表逐行 diff,统一到字节再比 |
| 分区尺寸未对齐擦除块边界 | 能读但写入报错;UBI attach 失败;分区尾部数据丢失 | 按 MB 取整,没有按 block / PEB 大小对齐 | 所有边界按块大小向上取整对齐(块大小以 datasheet 为准) |
| 单位混用:MB vs sectors vs 块号 | 偏移差一个数量级,或正好差 512 倍 / 1024 倍 | 一边用 1000 进制一边用 1024 进制;扇区号与字节地址混写 | 分区表内部一律用字节;MB / sectors 只在展示层出现 |
3.3 立即动作
- 两侧各导出一份分区表,逐行 diff。烧录器侧从工程配置导出,驱动侧用
cat /proc/mtd与设备树 / 分区定义交叉核对;两份表的字段必须能一一对应。 - 统一到字节。把所有 start / size 换算成字节再比对,避免单位差异掩盖真实差异。
- 把所有边界向上对齐到擦除块 / PEB 边界。这一步要按器件 datasheet 的块大小与平台 PEB 大小来算。
- 确认分区表是同一份文件。固件侧与烧录侧必须引用同一个版本化文件,不允许各存各的副本。
- 改完全片重烧,装板实跑验证。只看烧录器校验通过不算数。
单位错位的典型指纹是偏差恰好是某个整数倍:正好差 512 倍(sectors 与 bytes 混用)、正好差 1.024 倍(1000 进制与 1024 进制混用)、正好差一个块大小(块号与字节混用)。
出现这种「整齐的偏差」时,先怀疑单位,不要先怀疑器件。这一条能省下大量换料、送检的时间。
铁律:分区表内部一律用字节;MB / sectors / 块号只允许出现在给人看的展示层,且必须在表头显式标注换算基数。
3.4 分区表模板
第 12.2 节给了一份可直接复制的分区表模板,核心是强制用字节做单位、强制标注对齐基准、强制标注 ECC 与坏块策略三列。 把这三列写进模板,可以让「单位混用」这类错误在评审阶段就被拦住,而不是等到产线。
4. 第 2 类:分区内镜像偏移错位
分区起点对了,不代表镜像在分区内部的位置也对。 bootloader、kernel、fs 三段各有各的偏移来源,而且这些偏移是叠加的: 分区表给的起点只是一层,镜像自带的 header / 容器头是第二层,坏块跳过留出的空洞是第三层。
4.1 机制:偏移是三层叠加的
现场最常见的错误是只盯最终地址:把分区起点调来调去,试图用一个数把三层偏差全补回来。 这在某些片上能对上(因为那几片恰好没有坏块),换一片就失效——因为第三层偏差是逐片变化的, 而第一、二层是固定的,用一个固定数去补一个变量,必然只能对上一部分片子。
4.2 三段的偏移来源与判据
| 段 | 偏移的常见来源 | 错位的典型原因 | 判据 |
|---|---|---|---|
| bootloader / SPL | 分区起点 + 镜像头(IVT / DCD / 容器头等,格式与长度以平台手册为准) | 烧录器把整镜像从分区起点写,驱动却到「分区起点 + 头长」去找 | SPL 能跑起来,但读不到下一级;或 BootROM 直接报找不到镜像 |
| kernel / 内核 | 分区起点 + 容器头 + 坏块跳过留出的空洞 | 被跳过的坏块数没有被算进偏移;换片后坏块数变了,偏移就变了 | kernel 起一半挂掉;或长时间等待根设备 |
| fs / 根文件系统 | 分区起点(UBI 层在自己管理 PEB 到 LEB 的映射) | 分区起点没有对齐 PEB;或卷头位置与驱动期望不符 | UBI attach 失败;报空卷;报坏 PEB |
4.3 判据采集命令
下面这组命令的用途是把驱动侧认定的分区与偏移取出来,与烧录器工程里的配置逐项比对。 命令名与输出格式随平台与内核版本而变,以所用系统的实际输出为准。
# 驱动侧视角:把分区与偏移取出来(命令与输出以所用平台 / 内核版本为准) cat /proc/mtd # 驱动侧看到的分区起点与大小(十六进制字节) cat /proc/partitions # 块设备视角的分区(注意:单位是块,不是字节) mtdinfo /dev/mtd2 # 该分区的擦除块大小、最小 IO 单位、OOB / spare 大小 ubinfo /dev/ubi0 # UBI 视角:PEB / LEB 数量与大小、可用块数 # 烧录器侧视角:把工程里的分区表导出成同样的字段 # 重点核对三列,必须完全一致: # start(hex byte) size(hex byte) eraseblock / PEB size # 任何一列不一致,先回第 3 章解决分区表,不要继续调镜像偏移 # 比对模板(两侧各存一份,用 diff 看差异) diff prog_partition.txt drv_partition.txt
把分区起点硬调若干个块,是现场最高频的临时手段,也是最容易埋雷的手段:它在没有坏块落在关键分区里的那批片子上是有效的,一旦换一片、换一批料,坏块分布变了,这个补偿量就错了。
正确的处理顺序是:先让两侧用同一份分区表(第 3 章),再让烧录器与驱动用同一套坏块策略(第 6~8 章),最后才谈镜像内部的 header 偏移。把这个顺序反过来做,问题一定会复发。