SFDP / CFI / Parameter Page 自适应识别
驱动如何靠参数表识别时序、Dummy 周期、容量与块结构,而不是写死器件 ID —— SPI NOR / 并行 NOR / SPI NAND / eMMC / SD 的参数表机制、解析引擎设计与验证方法 | 编制日期 2026-10-14
报告总结
存储驱动最常见的做法,是内置一张「识别码 → 参数」对照表:上电读一次器件 ID,查表拿到容量、页大小、Dummy 周期、块结构。这套做法在单一料号上工作得很好,直到换供方、换代、加档位——每次变化都要改代码、发版本、重新回归,任何一次漏更新,现场就是「时好时坏的偶发故障」。
这份文档讲另一条路:让器件自己说,驱动负责听。SPI NOR 用 SFDP(JEDEC JESD216 系列)把能力写进结构化参数表;并行 NOR 用 CFI 查询序列回传参数结构;SPI NAND 用 Parameter Page 描述时序、ECC 与 OOB;eMMC / SD 用 ext_csd 与 CIS 元组链声明能力位。四者表结构不同,驱动侧动作却是同一条主线:发现、校验、生效。
本文面向存储固件与驱动工程师:每种接口的表长什么样、哪些字段关键、解析引擎怎么设计、失败怎么降级、上电时序怎么整合、版本漂移怎么防、怎么把「新器件零驱动改动」变成可验证的事实。文中不写死寄存器地址、位域位置与命令码数值,一律以器件 datasheet 与正式规范为准。
结论:写死 ID 的驱动,每一条新料都要求救;参数表驱动的每一条新料,只是一次回归。前提是把三件事做对:按版本解析而不是按固定偏移硬啃、关键字段三重校验后才敢用、失败时逐级降级且永不静默。做到这三点,换供方、换代、加容量档位都从「改代码」降级为「加样本」。
读者路径
- 想先建立全景:第 1 章(为什么不能写死 ID)+ 第 2 章(以 SFDP 为样板看表结构)。
- 正在写驱动:第 3、4、5 章(CFI / Parameter Page / ext_csd 与 CIS)+ 第 6 章(解析引擎)+ 第 7 章(时序参数推导)。
- 在整合上电与兼容:第 8 章(识别流程与上电时序)+ 第 9 章(兼容性策略与版本管理)。
- 在排故:第 10 章(常见坑与失效案例),按症状对号入座。
- 在建测试:第 11 章(测试与验证)+ 附录 B(伪码级流程)+ 附录 C(字段到配置映射)。
- 只要结论:第 12 章(十条结论与核查清单)+ 附录 A(参数表速查)+ 附录 D(规范编号)。
前言
这份文档讨论的问题,几乎每个存储驱动团队都遇到过:上电识别到底该「查表」还是「读表」。查表,是驱动内置一张识别码到参数的对照表,读到谁的 ID 就给谁的参数;读表,是驱动去读器件提供的结构化参数表,现场推导出参数。两条路都能让系统跑起来,差别全部发生在「料号变化」那一刻。
范围上,本文覆盖四类接口的参数表机制:SPI NOR 的 SFDP、并行 NOR 的 CFI、SPI NAND 的 Parameter Page、eMMC 与 SD 的 ext_csd 及 CIS / SDIO 元数据链;并覆盖驱动侧的解析引擎设计、时序推导、上电整合、兼容性策略与测试验证。不覆盖:具体寄存器位号与命令码数值(以 datasheet 为准)、厂商私有命令的逐条语义、UFS 的描述符与属性机制、文件系统与 FTL 层话题。
写作口径上,全文遵守三条约束:不写死寄存器地址、位域位置与命令码数值,只写机制、标准编号、配置顺序与条件量级,数值标注「以正式 datasheet / 规范为准」;不写商业数据;引图只用文字,按「第 N 章」引用,不做超链接。文中容量、页大小、块大小均为量级示意,落到设计请以 datasheet 与 JEDEC / ONFI / SD 协会等正式规范为准。
1. 为什么不能写死器件 ID
写死 ID 的本质,是把「器件的知识」以硬编码形式钉在驱动里。它在料号稳定时是最简单的方案,却把每一次物料变化都变成一次软件变更。这一章把写死 ID 的四种失效场景摆到桌面上,说明参数表思想为什么是共同解,并给识别失败定好代价分级。
- 写死 ID:驱动内置「识别码 → 参数」表,上电读 ID、查表、配置,三步完成。
- 参数表自适应:驱动内置解析逻辑,上电读参数表、校验、推导配置,换料时代码不动。
本章先立论:为什么前者的失效不是偶发而是结构性的,以及后者的收益与代价如何权衡。
1.1 写死 ID 的四种失效场景
下图把四种失效场景画在一起。它们的共同点不是「概率低」,而是一旦发生,驱动没有任何自我纠正的余地——参数已经按错误的值配下去了,后续所有读写都建立在这个错误之上。
四种场景逐一说明:
- 换代不通知:器件工艺或设计换代后参数表内容变了,但识别码为了兼容性保持不变。驱动拿老参数配新器件,轻则时序偏紧、重则高速档位完全读不出。这类问题在现场最难查,因为「同型号」三个字让人放弃怀疑器件。
- 二供切换:第二供应商的管脚兼容封装、识别码不同,驱动对照表里没有这一条。此时驱动要么把器件当坏件拒绝启动,要么落入一个错误的默认参数——后者比前者更危险,因为它能跑一段时间。
- 容量档位密铺:同家族往往有 1 / 2 / 4 / 8 Gb 多个档位,识别码之间只差少数几位。漏判一个档位,容量就探测错,表现为地址回绕、越界写、镜像数据——都是「容量猜错」的经典症状。
- 兼容料子集:第三方兼容片的命令集常常是全功能的子集,参数表缺字段或改用厂商自定义表。驱动按全功能假设去配,平时正常,直到某条命令或某个压测场景才暴露。
| 失效场景 | 触发条件 | 典型症状 | 参数表为什么能解 |
|---|---|---|---|
| 换代不通知 | 同容量换代,参数表变、识别码不变 | 高速档位下读写偶发失败 | 时序与 Dummy 从表里读,换代自动跟随 |
| 二供切换 | 管脚兼容、识别码不同 | 驱动无此条目,拒绝启动或配错 | 新供方同样提供参数表,解析即用 |
| 容量档位密铺 | 同家族多档位,识别码差几位 | 容量探测错,地址回绕 | 容量字段由表声明,不靠识别码猜 |
| 兼容料子集 | 命令集子集、字段缺失 | 特定命令或压测才暴露 | 缺字段有校验与降级,不会硬配 |
需要强调:这四种场景没有一种可以通过「把对照表维护得更仔细」来根治。对照表的维护成本随料号数量超线性增长——每加一个料号,要确认它和已有料号的每一项差异,而这种确认恰恰是最容易出错的环节。参数表路线把这个成本挪给了器件:差异写在器件里,驱动只负责读。
1.2 参数表思想的共同点
SFDP、CFI、Parameter Page、ext_csd / CIS 看起来是四种完全不同的东西:一个走 SPI 命令、一个走并行查询序列、一个要先页读再顺序吐字节、一个要切换模式才能读。但把它们并排放在一起,会发现驱动侧的动作完全同构——都可以归纳成发现、校验、生效三个阶段(见第一章的参数表思想总览图)。
三个阶段的含义:
- 发现:把参数表从器件里原样读出来。SFDP 是读表头拿指针再逐表读;CFI 是写查询序列进识别模式再顺序读;Parameter Page 是页读进 cache 再从偏移零顺序读;ext_csd 是发一条模式切换命令把一整块寄存器读回来。形式不同,动作一致。
- 校验:确认读到的就是能用的。签名、校验和、版本号、表长、交叉一致性——每种接口都有自己的一套,但没有任何一种可以跳过。
- 生效:把字段变成驱动配置。与默认值合并、未知字段跳过、产出统一配置对象。这一步决定了「换料不改代码」能不能真正落地。
更深一层的共同点是责任划分:参数表路线下,器件负责准确描述自己,驱动负责怀疑地读。怀疑地读,意味着任何字段在被采用前都要过校验,任何对不上都要有明确的动作,而不是默默采信。
| 接口 | 自述载体 | 签名 / 校验手段 | 扩展方式 |
|---|---|---|---|
| SPI NOR | SFDP 表(表头 + 参数表) | 固定签名 + 表长 + 版本号 | 追加新参数表,不改旧表 |
| 并行 NOR | CFI 参数结构 | 查询标识「QRY」+ 命令集 ID | 保留区扩展,版本号声明 |
| SPI NAND | Parameter Page | 页签名(ONFI 为「ONFI」)+ 校验和 | 厂商扩展区,版本号声明 |
| eMMC / SD | ext_csd / CIS 元组链 | 寄存器版本 + 元组链结构 | 新能力位追加,老位保留 |
这张表还有一个隐含结论:四种接口的「扩展方式」都是追加式而非重排式。这不是巧合,而是参数表路线能长期演化的前提——只有追加式扩展,老驱动读新表时才可能安全地跳过未知字段。第 9 章会把这个性质作为版本管理的基础。
1.3 自适应识别的收益与代价
参数表路线不是免费的。把收益与代价摆在一起,才能定下来在什么项目上值得做、做到多深。
| 维度 | 写死 ID | 参数表自适应 | 代价与缓解手段 |
|---|---|---|---|
| 换第二供方 | 要加条目、发版本 | 解析即用 | 需回归矩阵覆盖新供方样本 |
| 同家族多档位 | 逐档位维护条目 | 读容量字段自动获得 | 档位边界要有断言兜底 |
| 时序随频率变化 | 按频率手工配参数 | 读 Dummy 与档位字段 | 解析代码更复杂,需要黄金值比对 |
| 首次启动耗时 | 接近零(直接查表) | 多一次读表与解析(毫秒级) | 解析结果可缓存,见第 6.5 节 |
| 代码体积 | 小 | 解析引擎占一份固定成本 | 一次投入,全接口复用 |
收益侧最容易被低估的是「一次回归代替一次发版」。写死 ID 路线下,每加一个料号都要走「改代码 → 评审 → 发版 → 现场升级」的完整链路;参数表路线下,同一动作变成「样本入库 → 跑回归 → 确认全绿」。前者以天计,后者以分钟计,而且后者是可以自动化的。
代价侧最容易被高估的是「读表慢」。一次参数表读取加上解析,典型在毫秒级,相对整个启动流程占比很小;真正需要权衡的是第 8 章讨论的探测窗口与第 8.4 节的启动时间预算——那些场景下才值得把识别拆成两段或做缓存。
要不要上参数表路线,问三个问题:① 这个产品生命周期内会不会换供方或加档位?② 驱动的拥有者(你)和料号的决定者(采购 / 硬件)是不是同一个人?③ 现场故障的召回成本有多高?
三个问题里有两个答案是「会 / 不是 / 高」,参数表路线就是必选项而不是可选项。它的全部代价都在开发期,而它的全部收益都在变更期——没有变更的项目才适合写死 ID。
1.4 识别失败的代价分级
自适应识别一定会遇到失败——器件不支持参数表、总线干扰读回乱码、版本太新解析不了。设计的好坏不取决于「会不会失败」,而取决于失败时有没有分级、每一级有没有明确动作、整条链路上有没有一处是静默的。
| 等级 | 触发条件 | 固件行为 | 现场表现 |
|---|---|---|---|
| L0 可替换 | 参数表失败,白名单命中 | 套用白名单配置继续启动 | 无感,仅日志留痕 |
| L1 可降级 | 非关键字段异常或缺失 | 保守默认值 + 告警上报 | 功能可能少一档,系统仍可用 |
| L2 要止损 | 关键字段(容量 / 时序)异常 | 拒绝写、降为只读或挂起访问 | 启动变慢或进入安全模式 |
| L3 视为不在位 | 总线级无响应 | 跳过该器件,继续枚举其它 | 设备树少一个节点 |
分级的核心原则有三条:
- 关键字段与非关键字段分开:容量、页大小、块结构、Dummy 这类字段错了会毁数据,必须 L2;厂商自定义的能力字段错了最多少一档功能,可以 L1。字段分级表要写进设计文档,而不是留给实现时临场判断。
- 每一级都要有动作:降级不是「算了」,而是「用保守值继续 + 留下可诊断的记录」。没有记录的降级等于静默错配,比直接失败更糟。
- L3 之前必须有重试:单次读表失败很可能只是上电瞬态或总线抖动,直接判死刑会造成「偶发不上电」的顽固故障。
四级里没有「静默错配」这个选项,因为它不是降级而是事故:驱动以为自己拿到了正确参数,实际没有,然后按错参数读写。页大小猜错时的表现就是典型的静默错配——页内访问完全正常,只有跨页才错位,而且错位后的数据看起来「差不多对」,第 10.1 节会完整复盘这个案例。
防静默错配只有一招:关键字段之间必须能互相验证。容量要和地址模型对、页大小要和地址步进对、块结构要和擦除类型数对——任何一对矛盾,都不能采信,直接走降级。
1.5 本文件的覆盖接口
本文覆盖四类接口的参数表机制与一套通用解析引擎。按下表对号入座,可以快速找到自己关心的章节。
| 接口 | 标准 / 规范 | 参数表载体 | 主要讨论章节 |
|---|---|---|---|
| SPI NOR | JEDEC SFDP(JESD216 系列) | SFDP 表头 + 参数表指针 + 多张参数表 | 第 2 章、第 6 章、第 7 章 |
| 并行 NOR | JEDEC CFI(Common Flash Interface) | CFI 查询序列 + 参数结构 | 第 3 章 |
| SPI NAND | ONFI 及厂商 Parameter Page | Parameter Page(页读 + 顺序读) | 第 4 章 |
| eMMC | JEDEC eMMC(JESD84 系列) | ext_csd 寄存器块 | 第 5 章、第 6 章 |
| SD / SDIO | SD 协会物理层与 SDIO 规范 | CIS 元组链 / SDIO 元数据 | 第 5.3 节 |
不在覆盖范围内的内容,以及为什么:
- 具体寄存器位号与命令码数值:随型号而变,写进文档反而有害,一律以 datasheet 为准。
- 厂商私有命令的逐条语义:属于厂商文档的职责,本文只讨论「私有扩展区要不要解析」的策略(第 2.4、4.5 节)。
- UFS 的描述符 / 属性机制:与 Flash 参数表是另一套范式,另有文档讨论。
- 文件系统与 FTL:属于参数表之上的层级,本文只在接口处提一句衔接。
虽然按接口分章,但全文有一条暗线:第 2 章用 SFDP 把「表结构」讲透,后面每一章都对着这个样板找对应物——CFI 的查询标识对应 SFDP 的签名,CFI 的命令集 ID 对应参数表指针的表 ID,Parameter Page 的校验和对应表长检查,ext_csd 的能力位对应能力字段。找到对应物,四种接口就只需要学一次。
2. SPI NOR 的 SFDP 结构
SFDP(Serial Flash Discoverable Parameters,JEDEC JESD216 系列)是参数表路线里最成熟的样板:器件把能力写进一组结构化参数表,驱动按表头给出的指针逐表读取。本章以 SFDP 为样本,把「表长什么样、哪些字段是关键字段、版本怎么协商」讲透——后面三章的所有接口,都可以对照这一章找对应物。
- 表头:签名、版本、参数表指针个数,是整张表的地图。
- 参数表:基本表(容量 / 块 / 时序 / Dummy)+ 各类扩展表(4 字节地址 / 状态控制 / 厂商自定义)。
2.1 SFDP 表头与参数表指针
驱动对一颗 SPI NOR 发出 SFDP 读命令后,从地址零开始读回的第一段是表头。表头的任务是当地图:告诉驱动这是不是 SFDP 表、按哪个版本的结构理解、随后有几张参数表、每张表在哪里。
| 表头字段 | 作用 | 解析动作 |
|---|---|---|
| 签名(固定四字符) | 确认读到的是 SFDP 表而非随机数据 | 不匹配即回落,不继续解析 |
| 版本(主 / 次) | 决定表头与指针的结构口径 | 按版本选解析路径 |
| 指针个数(以减一形式存放) | 声明随后有几个参数表指针 | 决定读几个指针、最多几张表 |
| 保留字节 | 规范预留 | 忽略但记录,供未来诊断 |
表头之后是参数表指针数组:每个指针定长,含表 ID(其中一个标志位区分 JEDEC 定义表与厂商自定义表)、该表的版本号、表长(以固定粒度计)与段内偏移。驱动用「表头地址 + 偏移」算出每张表的绝对地址,用表长做边界检查——表长是防越界读的第一道闸,没有它,一个损坏的偏移就可能把驱动引到任意位置。
三个容易踩的细节:
- 指针个数为零:合法但意味着没有任何参数表可读,驱动只能回落白名单或保守默认。
- 表长与偏移重叠:两张表的区域重叠,说明表或指针已损坏,必须判校验失败而不是「先凑合用」。
- 指针顺序不固定:不要假设第一张就是基本表,按表 ID 找,按下标找是经典错法。
SFDP 读命令是一条普通 SPI 命令,但它有自己的时序要求:部分器件只在低速档位支持读表,高速档位下要先降速或切回默认模式再读。「上电后第一件事就读表」在电气上并不总是成立,读不到表时不一定是器件不支持,也可能是当前模式不对。具体支持情况以 datasheet 为准,第 8.1 节会把这件事并入上电时序讨论。
2.2 基本参数表的核心字段
基本参数表(JEDEC 定义、表 ID 由规范分配)是 SFDP 的核心,驱动需要的绝大多数配置都在里面。按用途可以把字段分成五族:
- 容量与地址族:声明密度与地址位数,决定 3 字节地址是否够用、要不要走第 2.3 节的 4 字节地址路径。
- 块结构族:统一擦除块大小,以及一到四种擦除类型各自的大小与配套命令。异构块(如上大下小)在这一族里声明。
- 页与写族:页大小、写使能与页编程的时序要求。
- 时序与 Dummy 族:各档位下的 Dummy 周期数、模式位定义,是第 7 章的主题。
- 状态与控制族:状态寄存器布局、写使能序列、4 字节地址进入 / 退出命令的存在性。
基本参数表里的很多字段是能力声明而非当前状态。器件声明支持 4 字节地址,不代表它已经处在 4 字节模式;声明支持某高速档位,不代表控制器已切过去。驱动要把「声明」当入口条件,把「状态寄存器 / 模式位」当当前值,两者交叉核对后才敢用——只信声明会配出器件不认的参数,只信状态又会错过可用能力。
从字段到配置的映射,是第 7 章的主题;这里先建立一条判据:凡是影响「数据落在哪、以多大粒度落」的字段,都是关键字段——容量、页大小、块大小、擦除类型、Dummy。这些字段错一个,表现都是静默错配或直接读失败,因此必须过交叉一致性校验,而不能单独采信。
2.3 4 字节地址与状态控制扩展表
3 字节地址覆盖到 4 GiB(即 32 Gb)量级,容量再往上就必须切 4 字节地址。JESD216 为此定义了 4 字节地址扩展表:声明器件是否支持、支持哪些进入 / 退出命令、以及命令是易失还是非易失的。驱动据此选择切换路径,而不是假设某一种。
状态控制扩展表则把状态寄存器的布局、各状态位的含义、写使能序列的要求集中声明出来。它的价值在于解耦:驱动不必把「先写使能再写寄存器」这类顺序硬编码成某一种固定舞步,而是按表的声明走。
切到 4 字节模式后,后续所有带地址的命令都按 4 字节解释;此时若发一条按 3 字节解释的命令,地址会被错位吞掉。切换路径上任何一步失败(例如写完使能但没切模式),都必须能退回 3 字节模式,否则器件卡在中间状态,后续访问全部失效——现场表现是「突然整片读不出,复位后恢复」。
工程上的稳妥做法:把模式当作识别状态的一部分显式记录,切换前后各读一次状态寄存器确认,失败即回退并走降级路径(第 6.4 节)。
2.4 厂商自定义表的取舍
厂商自定义表(表 ID 落在厂商号段)放的是私有能力:特定高性能模式、安全寄存器布局、QEP 之类扩展命令集。驱动面对它有三種态度,选哪种是产品策略而非技术问题:
- 默认不解析:把未知表记下 ID 就走。功能最少,但稳——不会因为猜错私有表结构而配出危险参数。
- 按需解析:确需某功能时,按「厂商 + 表 ID + 版本」三元组启用对应解析器,其它表仍不碰。
- 激进解析:尝试解析所有未知表。除研究场景外不推荐——私有表结构没有规范约束,猜错的代价是静默错配。
最实用的折中是记录所有未知表的 ID 与版本,但一个都不解析。这样做的收益有两层:一是现场诊断时能立刻看出「这颗料带了哪张私有表」,把「偶发故障」的排查范围缩到具体能力上;二是为新器件预留了决策点——等样本攒够、确认要支持某功能时,再按三元组打开对应解析器,而不是一開始就把所有私有表都当成必须吞下的。
2.5 表版本协商与兼容
SFDP 的版本分两层:文档级(表头里的主 / 次版本)与表级(每个指针里带的版本号)。两层共同决定字段布局,任何一层对不上,解析路径都要变。
| 组合 | 风险 | 正确做法 |
|---|---|---|
| 新驱动读旧表 | 按新布局解析会整体错位 | 按表声明的版本走旧路径,缺的字段补默认值 |
| 旧驱动读新表 | 新字段被当保留区忽略 | 按表长截断,未知字段跳过并记录 |
| 同一颗料多张表版本混用 | 回归时难复现、难定位 | 把每张表的版本纳入识别结果一起上报 |
贯穿三种组合的一条铁律:按版本解析,不按固定偏移硬啃。固定偏移之所以诱人,是因为它简单;它之所以危险,是因为字段布局本来就是版本相关的——新版本插入一个字段,后面所有字段全部平移,而硬啃的驱动毫无察觉。第 6.3 节会把这个思想推广成解析引擎的通用规则。
版本协商还有一个常被忽略的出口:表声明的长度与指针声明的偏移矛盾时,以严格者为准。宁可按短了解析、少用几个字段,也不要按长了解析、读到相邻表的数据里去。
3. 并行 NOR 的 CFI 查询
CFI(Common Flash Interface)让并行 NOR 在查询态中自述容量、擦除区域、时序与命令集。驱动要做的不是记住某颗器件的固定答案,而是可靠进入查询态、连续验证 QRY、按规范反算字段,并在任何出口都恢复正常读模式。
CFI 的价值在于把「这颗器件属于哪种组织、要等多久、该用哪套命令」放进器件自身。它和普通阵列读取共享同一组地址与数据线,却使用不同的地址映射,因此查询动作本身必须被当成一次受控的模式切换,而不是若干个孤立的读周期。
驱动实现时应同时关注入口、内容与出口:入口决定读到的是参数还是阵列数据;内容决定容量与擦写策略;出口决定后续擦写命令会不会被错误地解释。
- 先验真值只有签名:连续读到 Q、R、Y,才说明查询态与总线视图基本正确。
- 几何与时序缺一不可:前者决定访问边界,后者决定 wait-state 与超时策略。
- 命令集 ID 只负责分流:它选择驱动实现,不会替驱动完成擦除、编程与状态轮询。
- 退出是显式动作:读完参数不会自动回到普通阵列模式。
3.1 CFI 查询序列与识别模式
进入 CFI 查询态的基本思想,是按器件支持的总线组织向规范指定的地址窗口写入查询序列。器件识别该序列后,不再把后续读取解释为普通阵列访问,而是在查询映射中返回结构化数据。具体写入地址、命令值、周期要求与位宽适配必须以器件 datasheet 和正式 CFI 规范为准;驱动层不应把某一颗样片的总线波形当作所有器件的通用答案。
查询态最先要验证的是连续 ASCII 签名「QRY」。它是器件对「我支持 CFI,而且你当前看到的是正确查询视图」的自述。校验必须按 Q、R、Y 三个字节的顺序逐一比较,并确认它们位于预期的连续查询位置。只看首字节会把阵列数据中的偶然命中、浮空总线上的固定电平、甚至地址线错位后的镜像值误判为有效 CFI。
查询态的地址映射与正常读模式不同:相同的外部地址线组合,在查询态可能代表签名、版本、命令集或几何字段,在普通读模式则代表 Flash 阵列内容。驱动必须把当前模式写进状态机,任何参数读取都只能发生在「已进入、签名已通过」之后;同理,任何普通读取、擦除或编程都只能发生在「已确认退出」之后。
不支持 CFI 的器件通常不会给出一个整齐的错误码。它可能返回阵列原值、全零或全一、随总线保持而变化的静态噪声,或者在多次读取中表现出不稳定。正确处理不是尝试解释这些字节,而是对签名做重复读取与一致性检查;连续签名不成立就判定 CFI 不可用,先退出查询尝试,再转入传统 ID、白名单或人工配置路径。
| 校验点 | 通过条件 | 失败含义 | 驱动动作 |
|---|---|---|---|
| 查询入口 | 写序列完成且总线周期正常 | 模式未切换或总线组织不符 | 先执行退出 / 复位,再按位宽重试 |
| QRY 签名 | 三个字节连续、顺序与内容均匹配 | 不支持 CFI、地址错位或仍在阵列态 | 停止解析,不以单字节命中放行 |
| 重复读取 | 多次读回稳定一致 | 浮空、保持值或时序边界不稳 | 降速 / 增加等待后重试并留痕 |
| 参数边界 | 表长、指针和查询窗口相互自洽 | 结构损坏或版本口径不匹配 | 放弃 CFI,进入兜底路径 |
| 退出确认 | 普通阵列读恢复为预期内容 | 仍停留在查询态 | 禁止擦写,执行规范复位流程 |
表中的任何一个失败都不等价于「器件损坏」。CFI 不可用与器件不可用是两个结论:前者只说明自述路径没有建立,仍可通过传统 ID 或人工配置完成识别;只有总线级无响应、退出后仍无法正常读取,才应升级为器件不在位或硬件故障。
3.2 CFI 参数结构:时序、容量、块结构
QRY 通过后,参数区可以按用途拆成三个信息族。第一族是几何与组织:器件总容量采用规范定义的指数或编码表达,配合每字位数、写缓冲页数与页大小,还会给出擦除块区域描述结构。每个区域描述「区域内块数 + 块大小」,多个描述拼起来即可表达底部小块、顶部小块或其它异构块布局。解析时要先还原每个区域,再把区域容量求和,与总容量字段交叉核对。
第二族是异步时序:读取周期、单字或缓冲编程耗时、扇区 / 块擦除超时工程量等。CFI 往往同时给典型值与最大值,并以 BCD、指数或规范编码保存;驱动必须按字段定义反算,不能把原始编码直接当时间,也不能用典型值充当失败超时上限。典型值适合性能预算,最大值才适合轮询超时与看门狗边界,具体数值以正式 datasheet / 规范为准。
第三族是电气与模式相关信息:VCC / VPP 的上下限、单电源或双电源编程形态,以及「地址建立到输出有效」这类异步接口条件。它们不是拿来直接替代板级 SI 与电源验证的,而是决定驱动是否可以启用某种编程路径、控制器是否需要增加等待状态。所有电压、时间与编码换算均以目标器件 datasheet 和正式规范为准。
工程上最关键的判断是:几何与时序必须同时拿到。只有几何没有时序,驱动知道数据在哪里,却不知道控制器该等多久;只有时序没有几何,驱动能稳定读,却可能在错误边界上擦除。任何一族关键字段缺失、越界或相互矛盾,都应阻止配置对象进入「可写」状态。
| 信息族 | 关键内容 | 主要产物 | 交叉校验 |
|---|---|---|---|
| 几何 / 组织 | 总容量、字位组织、写缓冲、擦除区域 | 容量边界、页粒度、块区域表 | 区域容量求和应与总容量相容 |
| 异步时序 | 读周期、编程时长、擦除典型值与最大值 | wait-state、轮询间隔、超时上限 | 最大值不得小于典型口径 |
| 命令集 | 主命令集与扩展查询表指针 | program / erase / status 分发表 | 命令集与扩展表签名 / 版本对应 |
| 电气 / 模式 | VCC / VPP 范围、编程供电形态、接口条件 | 模式准入条件与板级约束 | 当前板级电气条件必须落在声明范围 |
| 版本 / 保留区 | 结构版本与未来扩展空间 | 选择解析器、跳过未知字段 | 按版本和表长截断,不猜保留位 |
典型值回答「大多数操作多久完成」,最大值回答「最慢合法器件多久仍算正常」。调度器可以用典型值安排首次轮询,但故障判定必须以最大口径并结合系统裕量。把两者写进同一个变量,会让快器件被频繁空轮询,也会让慢器件被误判超时。
CFI 的原始编码可能不是线性数值。解析器应先生成带单位与口径的中间量,再由第 7 章的映射层生成控制器配置;编码定义与数值边界以正式规范为准。
3.3 命令集匹配与退出查询
CFI 参数区会给出命令集 ID,声明器件采用哪一套擦写与状态控制语义。常见家族包括 Intel Standard / Extended、AMD / Fujitsu Standard 等,另有规范统一分配的其它集合。这个 ID 的作用是选择驱动实现:告诉你该去哪张分发表找函数,却不会替你发送写使能、擦除、编程或状态轮询动作。
拿到命令集 ID 后,应在分发表中查找完整的一组实现:进入编程、单字 / 缓冲编程、擦除、读状态、清错、挂起 / 恢复(若支持)与复位退出。不能只因为「读正常」就认为命令集已支持;真正的准入是擦写路径和异常恢复路径都存在。扩展查询表还要通过签名、版本与边界校验,具体以正式 CFI 规范及器件 datasheet 为准。
若命令集 ID 不落在已知集合,安全策略是把器件保留在只读或未绑定状态,上报「未知命令集 + 原始参数摘要」,再尝试白名单提供的显式实现。绝不能把未知 ID 强行映射到「最像的一套」命令:并行 NOR 命令状态机容错空间很小,错误的擦除或复位序列可能让后续访问全停在忙、错误或自动选择态。
| 匹配阶段 | 判断 | 允许动作 | 禁止动作 |
|---|---|---|---|
| ID 已知且实现完整 | 分发表含擦写、状态与恢复函数 | 创建可读写配置并继续验证 | 跳过退出确认直接擦写 |
| ID 已知但实现不完整 | 缺少错误恢复或缓冲编程路径 | 按能力降级为已实现子集 | 调用空缺路径或假设命令兼容 |
| ID 未知但白名单命中 | 人工配置明确绑定命令集 | 按白名单启用并记录覆盖来源 | 静默覆盖 CFI 差异 |
| ID 未知且无兜底 | 没有可信命令语义 | 只读、拒绝绑定或报告不支持 | 尝试性擦除 / 编程 |
CFI 查询态不会因为「读够一定字节」自动结束。退出必须使用规范为当前命令集规定的复位 / 退出动作,并在退出后用可预测的阵列内容确认模式已恢复。查询态未退出就发擦除或编程,是并行 NOR 驱动最典型的死锁来源之一:器件仍把地址解释为查询偏移,驱动却在等待永远不会出现的忙状态变化。
因此,退出动作必须放在统一清理路径:成功、签名失败、字段损坏、未知命令集和超时都走同一个出口。具体复位序列以器件 datasheet / 正式规范为准。
退出确认也不能只靠「命令已发送」。建议在进入查询前保存一个稳定的普通阵列读取样本,退出后重新读取并比较;若样本不可预知,则至少验证 QRY 映射已经消失且普通读时序恢复。确认失败时,应立即禁止擦写并升级故障,而不是再次叠加另一套命令序列。
3.4 CFI 与写死 ID 的兼容处理
CFI 并不要求把传统 ID 路线全部删除。两条路径可以共存,但要明确谁提供参数、谁提供身份。推荐顺序是:先走 CFI,只有 CFI 无法建立可信配置时才落到传统 ID。这样,新器件只要正确实现 CFI 就能被识别,旧器件或异常样片仍有兜底,不会因为迁移架构而失去存量兼容。
当 CFI 成功时,容量、块区域、时序与命令集都应来自 CFI;传统 ID 仅作为「备注与追溯」写进识别结果,用于日志、样本归档与问题定位,不参与参数决策。把 ID 继续留在参数分支里,会形成两个真值源:某些字段取 CFI、某些字段取旧表,最终很难解释配置从哪里来。
若 CFI 与传统 ID 对应的内置描述冲突,应以通过完整校验的 CFI 为准,同时上报差异:字段名、CFI 解析值、旧表值、器件身份与固件版本都进入诊断记录。不能静默择一,因为冲突本身往往意味着换代、手册修订、旧表错误或参数页损坏,是第 9 章版本管理必须捕获的信号。
| 场景 | 参数来源 | ID 的作用 | 处理结果 |
|---|---|---|---|
| CFI 完整有效 | CFI 几何、时序与命令集 | 仅备注、追溯与样本索引 | 按 CFI 生成配置 |
| CFI 签名失败 | 传统 ID 对应白名单 | 选择明确审核过的配置 | 记录 CFI 不可用后继续 |
| CFI 关键字段损坏 | 人工配置 / 白名单 | 辅助锁定适用规则 | 降级并禁止静默高性能配置 |
| CFI 与旧表冲突 | 校验通过的 CFI | 标识冲突器件与历史条目 | 采用 CFI,同时上报差异 |
| 两条路径都未知 | 无可信来源 | 仅保留原始身份数据 | 拒绝写或判不支持 |
白名单 / 配置文件不是参数表架构的失败,而是工程系统的保险丝。它应能按稳定身份与板级条件覆盖少量已确认问题,同时记录覆盖版本、原因和适用范围。白名单条目必须显式、可审计、可回滚;不能退化成另一张无限增长的写死 ID 大表。
正确的定位是:CFI 提供默认真值,修正表处理已知错误,白名单承接完全不支持 CFI 的旧器件。三层来源要在最终配置对象里保留 provenance,便于第 11 章回归工具判断配置究竟从哪里来。
兼容处理还要避免「失败后直接读 ID」的模式污染。每次从 CFI 路线切到 ID 路线前,都必须先走统一退出流程并确认阵列模式恢复;否则传统 ID 命令可能在查询态中被当成偏移读取,得到一组看似稳定但完全错误的身份字节。
3.5 CFI 实现的厂商差异
CFI 主表只负责公共能力,厂商差异通常放在主 / 备用命令集对应的扩展查询表中。扩展表由指针定位,带有自己的签名与版本,并描述该命令集的附加状态、缓冲编程、保护或挂起能力。驱动应把它当成受版本约束的附表,而不是在主表之后继续按固定偏移盲读。
解析顺序建议为:先验证主命令集及其扩展表;主表完整就以主表为准。主扩展表缺失或损坏时,才检查备用命令集与备用扩展表;两者都缺时,保留公共几何并按能力降级,不猜厂商私有语义。每张扩展表都要独立校验签名、版本、指针范围和表长,具体字段布局以对应器件 datasheet / 正式规范为准。
真实器件还可能出现字段写错、位义与手册描述相反、典型值和最大值颠倒、区域数量与总容量不一致等问题。例如某个能力位在参数表中声明为支持,实测和手册却都表明该功能关闭;也可能位值与文字定义相反。解析器不能在通用代码里散落「如果是某型号就取反」的特判,否则修复不可审计、也无法随固件版本追踪。
| 差异类型 | 识别信号 | 默认策略 | 可接受修正 |
|---|---|---|---|
| 主扩展表有效 | 签名、版本、指针与长度均通过 | 按主命令集解析 | 无 |
| 主表缺失、备用表有效 | 备用命令集与附表完整 | 降级到备用实现并上报 | 记录选择来源 |
| 扩展表版本未知 | 签名正确但版本超出解析器范围 | 只用公共字段,跳过未知尾部 | 后续增加版本化解析器 |
| 能力位与手册相反 | 实验、手册与参数表形成稳定冲突 | 先禁用该能力并报告差异 | 进入第 9.4 节修正表 |
| 几何字段不自洽 | 区域求和、容量或对齐互相矛盾 | 判关键字段失败 | 仅允许审核过的精确修正规则 |
厂商差异只能通过第 9.4 节的修正表机制进入:匹配条件要包含稳定身份、参数表版本与必要的板级条件;修正内容要指明原值、目标值、证据和回归样本;应用后还要重新跑交叉一致性。没有这些元数据的修正,一律视为不可追溯特判。
对未知厂商区最稳妥的姿态是「记录但不解释」:保存原始字节、签名、版本和指针,供现场样本与后续解析器使用;当前固件只消费自己明确支持的版本。这样既不会错过诊断证据,也不会因猜错私有结构把器件带入危险模式。
4. SPI NAND 的 Parameter Page
SPI NAND 的 Parameter Page 把组织、时序、ECC、坏块与 OOB 责任放进一页结构化数据。解析的难点不只是读出字段,而是先完成 NAND 式页级事务,再用这些字段决定地址公式、Dummy、ECC 归属和坏块管理。
ONFI 定义了 Parameter Page 的概念与语义,SPI NAND 器件借用这套「整页自述」思路,再结合串行接口的命令、cache 与状态机制实现。不同器件对读取入口、地址与扩展区的规定可能不同,具体序列、长度和编码以正式 datasheet / 规范为准。
与 NOR 参数表相比,NAND 参数页更强调介质管理责任:不仅要知道容量和速度,还要知道 ECC 由谁做、OOB 能放什么、坏块标记在哪、驱动是否要建坏块表。
- 整页事务:发起参数页读取、等待内部操作完成、连续读回并校验。
- 组织决定地址:页、块、LUN 与平面字段共同构成行 / 列地址模型。
- ECC 与 OOB 是一组责任:不能只开 ECC 而不确认坏块标记和可用 OOB。
- 厂商区默认只留档:只有版本匹配且校验可用的字段才进入决策。
4.1 Parameter Page 的组织与读取
读取 Parameter Page 是一个完整事务:发送 Read Parameter Page 类命令,按器件要求给出地址(很多实现使用固定语义的单字节地址),等待器件内部操作结束,再从数据输出路径连续取回整页,最后做签名、版本、长度与校验。本文不写死命令码和地址值,具体序列、等待条件与页长以器件 datasheet / 正式规范为准。
等待阶段必须看 on-die 状态,而不是用固定延时猜测。与直接映射读取的 NOR 不同,NAND 的内部页操作可能经历忙态,并可能报告操作失败;驱动的判据应包含「不再忙」和「本次事务没有失败」两部分。只等时间、不看状态会把慢器件误判为无响应;只看忙位、不看失败结果又会把一页无效数据送进解析器。
页内字节流通常从签名与版本开始,随后按字段组放置组织、容量、时序、ECC、OOB 与能力描述,中间穿插保留区,尾部可能留给厂商扩展。保留区的存在意味着解析器不能按「上一个字段末尾紧接下一个字段」推算偏移,而要按版本化结构定义取字段;字段位置、长度与校验方式以正式规范为准。
推荐把整页一次性读回内存,再离线解析,而不是按字段分片读取。整页快照有四个收益:校验覆盖的是同一时刻的数据;版本与长度可以先决定解析器;任何字段越界都能在内存边界内被拒绝;原始页可以留档复现。分片读会把总线重试、状态变化与字段解析交织在一起,出了问题很难区分是读取不稳还是结构理解错误。
| 阶段 | 完成条件 | 主要失败 | 处理 |
|---|---|---|---|
| 发起参数页事务 | 命令与地址阶段被器件接受 | 模式不对、地址语义不符 | 复位接口后按 datasheet 重试 |
| 等待 on-die 就绪 | 忙态结束且操作失败状态未置位 | 内部读取失败或等待超时 | 放弃本次快照并记录状态 |
| 连续读回整页 | 达到声明 / 规范页长且传输稳定 | 少读、错位、总线抖动 | 整页作废,不拼接不同重试 |
| 签名与版本校验 | 签名、版本和边界均可识别 | 读到普通数据或结构版本未知 | 退出解析,走白名单 / 保守路径 |
| 校验与离线解析 | 校验通过且关键字段自洽 | 页损坏或字段互相矛盾 | 保留原始页,禁止配置生效 |
ONFI 提供的是参数页的组织思想和字段语义;SPI NAND 如何进入参数页、如何给地址、如何从 cache 输出,则由目标器件接口定义。解析器可以复用 ONFI 风格的数据模型,但传输层不能照搬并行 NAND 的操作。把「怎么读到」与「读到后怎么解释」拆成两层,是兼容多家 SPI NAND 的前提。
4.2 时序与 Dummy 字段
组织类字段决定地址公式的形状:页大小与备用区大小决定列地址覆盖范围;每块页数决定行地址步进到哪进入下一块;每逻辑单元块数与 LUN 数决定高位如何解释;每单元比特数影响介质类型、编程约束与性能预期。驱动应先把这些字段归一化为 page、block、LUN 三层几何,再生成地址位分配,不能先写死拆分再用参数填空。
最大工作速度档位字段通常不足以直接得到 Dummy。更稳妥的模型是维护一张最小化映射:接口模式 -> 该模式下的最小 Dummy 周期,再结合参数页声明能力、控制器所选频率与板级裕量选出实际值。不同模式可能共用频率上限却要求不同 Dummy,同一模式也可能随频率区间改变等待;具体以器件 datasheet / 正式规范为准。
Dummy 要分两类理解:一类是当前模式和频率下必须插入的最小值,少于它数据在采样点前尚未有效;另一类是接口或控制器能力允许的最大值,超过它可能无法表达或破坏事务格式。驱动应在两者之间选满足当前频率的最小安全值,并保留降频后减少 Dummy 的能力,而不是总取最大值掩盖时序问题。
| 输入字段 / 条件 | 推导目标 | 校验 | 失败策略 |
|---|---|---|---|
| 页大小 + 备用区大小 | 列地址范围与主 / OOB 分界 | 范围可表示且边界不重叠 | 拒绝 OOB 操作,保留只读诊断 |
| 每块页数 | 页地址到块地址的步进 | 块边界与擦除粒度一致 | 禁止擦除与跨块编程 |
| 每 LUN 块数 + LUN 数 | 行地址高位和总容量 | 乘法链不溢出且与容量声明相容 | 关键字段失败,停止绑定 |
| 接口模式 + 速度能力 | 可选工作频率集合 | 控制器与器件能力取交集 | 降级到共同支持的保守模式 |
| 模式到 Dummy 的映射 | 实际 Dummy 周期 | 落在最小需求与最大能力之间 | 降频后重新选择,不盲加周期 |
参数页声明的最高能力只表示「器件可能支持」,不是系统应直接采用的工作点。真正配置值还要与控制器采样能力、板级信号完整性、温度电压范围和 Dummy 映射取交集。任何具体频率、周期与裕量均以器件 datasheet、控制器手册和正式规范为准。
推导结果应保留证据链:所选接口模式、频率档位、最小 Dummy 来源、控制器上限与最终值都写入配置对象。后续出现高速读错时,日志能够直接回答「为什么选择这个 Dummy」,而不是只看到一个失去上下文的整数。
4.3 ECC、坏块与 OOB 布局字段
ECC 要求字段描述介质期望的纠错强度或等效能力,与「内部 ECC 是否启用」不是同一个问题。SPI NAND 常带 on-die ECC:启用时器件在页读 / 页编程路径里处理纠错,可能占用部分 OOB;关闭时主控或软件 ECC 要承担纠错、码字布局与状态解释。驱动必须按参数页与 datasheet 声明确定责任,不能因控制器有 ECC 就默认关闭内部 ECC,也不能因器件有 ECC 就假设 OOB 全部可用。
坏块标记位置字段告诉驱动在页内哪个字节或保留位置检查出厂坏块,该位置必须与内部 ECC / OOB 布局一起解释:若 on-die ECC 重排或保护 OOB,读坏块标记可能要特定模式;若外部 ECC 用同一区域,又可能覆盖标记。具体位置与读法以器件 datasheet / 正式规范为准,固定偏移不应跨型号复用。
OOB / 备用区字段至少要拆成「物理备用区总量」与「驱动可用字节」:前者是页几何的一部分,后者扣除内部 ECC、坏块标记与厂商保留区。文件系统或 FTL 只能看到可用部分;把物理总量直接上报上层,会在量产后才出现元数据覆盖 ECC 或坏块标记的故障。
| 参数页声明 | 决定的责任 | 驱动必须确认 | 错误假设的后果 |
|---|---|---|---|
| ECC 要求等级 | 所需纠错能力下限 | 内部 / 外部 ECC 能力是否满足 | 静默位翻转或过度保守 |
| 内部 ECC 能力 / 模式 | 纠错由器件还是主控执行 | 使能状态、状态码语义与 OOB 占用 | 双重 ECC 或完全无 ECC |
| 坏块标记位置 | 出厂坏块识别入口 | 标记所在页、列位置与读取模式 | 把坏块当好块投入使用 |
| 备用区总量 | 物理页尾空间 | 是否含厂商保留与 ECC 区 | 把保留区错误暴露给上层 |
| OOB 可用字节 | 上层元数据预算 | 布局与对齐是否可由控制器表达 | 元数据与 ECC / 标记互相覆盖 |
| 坏块管理能力 | 是否需要主机扫描和维护 BBT | 出厂标记与运行期新增坏块策略 | 坏块表遗漏或重复管理 |
ECC、OOB 和坏块不能分三个功能各自实现。正确顺序是:先确认 on-die ECC 是否必须启用,再确定谁放置 ECC 校验数据,随后冻结坏块标记保护范围,最后把剩余 OOB 暴露给上层。任何一步缺证据,都先把可用 OOB 收紧到保守值并禁止写入未知区域。
是否需要驱动做坏块表扫描,要看器件是否仅提供原始标记、是否有内部映射能力,以及系统上层是否已经承担 BBT。参数页若只声明标记位置而没有托管坏块管理,驱动就需要在初始化或受控后台流程中扫描并持久化;若器件明确完成内部管理,则主机只需处理接口暴露的失败。两种模型不能同时假设,否则会重复屏蔽容量或漏掉运行期坏块。
4.4 容量与地址模型字段
SPI NAND 的原始总容量可由组织字段形成乘法链:每页主数据字节数 × 每块页数 × 每 LUN 块数 × LUN 数。每步都用足够宽的整数并检查溢出,再与参数页容量描述、行地址位数和器件 ID 备注交叉验证。备用区不计入用户主数据容量,有效容量是原始总容量扣除页级备用、坏块与系统保留后的结果,不是物理字节简单相加。
「标称某个 MB 却按字段算不出同一个数」通常不是参数页错误,而是单位与口径混用:十进制与二进制容量单位不同,bit 与 byte 混用,标称容量可能指原始阵列而软件上报的是扣除备用区 / 坏块后的可用容量。文档与日志应同时标明单位、是否含 OOB、是否含保留块,具体以器件 datasheet / 正式规范为准。
地址模型要区分页地址与列地址:页地址选择阵列中的页,承载块、页、LUN 或平面相关高位;列地址选择页内主数据或 OOB 位置。驱动要根据「主数据 + 备用区」的最大列范围判断是否用双字节列地址(实现中常称 16 位列地址),而不是按容量大小猜。具体地址周期数、位分配与字节序以器件 datasheet 为准。
| 推导项 | 输入 | 输出 | 边界检查 |
|---|---|---|---|
| 页跨度 | 主数据字节 + 备用区字节 | 列地址合法范围 | 主区与 OOB 区连续且不重叠 |
| 块跨度 | 每页主数据 × 每块页数 | 块容量与页地址低位 | 与擦除粒度相容 |
| LUN 容量 | 块跨度 × 每 LUN 块数 | LUN 内行地址范围 | 乘法不溢出、块数非零 |
| 原始总容量 | LUN 容量 × LUN 数 | 器件原始主数据容量 | 与容量声明 / 地址位数相容 |
| 有效容量 | 原始容量 - 坏块 / 保留预算 | 上层可管理容量 | 单位与扣减口径必须显式 |
| 地址周期 | 页内最大列 + 行地址范围 | 列 / 行地址发送方式 | 控制器可表达且字节序一致 |
容量计算上可以相乘,命令执行上却可能需要额外选择。不同器件会把 LUN / 平面编码在内部行地址位、特定选择状态或独立片选语义中;某些并行操作还要求页地址满足平面对齐。驱动应把「几何高位如何编码」与「命令是否允许跨 LUN / 平面」分别建模,具体位分配与约束以 datasheet / 正式规范为准。
多 LUN / 多平面对工作方式的影响主要在并发、状态与失败归属:一条命令作用于哪个内部单元、忙状态是全局还是局部、失败码对应哪次操作,都需要由器件语义决定。容量字段只能证明这些单元存在,不能证明控制器可以并发访问;没有明确能力声明时,按串行、单目标方式执行最安全。
4.5 厂商扩展字段的取舍
Parameter Page 的厂商自定义区通常承载公共字段放不下的细节,例如出厂坏块预置信息、内建 ECC 的更详细能力、温度等级、特定读重试或接口增强说明。它的价值主要在诊断与精细调优,而不是成为基础识别的唯一来源;容量、页几何、最低 ECC 责任等关键结论仍应能从主表建立。
值得读并可能进入决策的字段,通常同时满足三个条件:有稳定的版本标识、字段语义写进正式 datasheet、并且能与主表或实测做交叉验证。出厂坏块预算、内部 ECC 责任与温度等级属于候选;而没有稳定版本、只服务于工厂筛选、或随固件 / 批次漂移的统计字段,应只读留档,不参与运行时参数。
处理原则可以概括为「读取仅尊重,校验可用才用」:传输层完整读回,不擅自截断;解析层先看厂商标识、修订版本、区间边界与可用校验;决策层只消费明确支持的字段。未知内容原样保存,不把零值或保留值解释为能力关闭,也不因为某个字段看起来合理就越过版本检查。
第一层,留档:保存原始字节、厂商标识和版本,所有器件都做。
第二层,诊断:把已知字段转成可读日志,但不改变配置。
第三层,决策:只有正式定义、版本匹配、校验通过且与主表一致的字段才允许进入配置对象。
三层必须可独立开关。这样既能积累样本,又不会让尚未验证的厂商字段悄悄改变量产行为。
当厂商区与主表冲突,默认以通过签名、版本与整体校验的主表为准,并记录冲突证据。若已确认主表存在器件级错误,应走第 9.4 节修正表:精确匹配版本、记录证据、应用后重跑一致性;不能在厂商区解析器里静默覆盖主表。
取舍的最终目标不是「解析字段越多越先进」,而是让配置来源可解释、可回归。一个只解析公共字段但每项都有证据链的驱动,通常比一个吞下全部厂商区却无法说明优先级的驱动更可靠。后续新增厂商解析器时,应把原始页样本加入第 11 章回归矩阵,确保旧版本仍按原策略处理。