修一只坏 U 盘那晚:FC3532 + N18,和我对"重读"的三次理解偏差

自己的一只 U 盘坏了,厂家把他们的官方量产工具发给我,授权我拿去修。2026 年 7 月 2 日凌晨,我和 Claude Code(旁边还开了一个 Gemini CLI)一起把这套工具拆开看,顺带把 NAND 重读的机制理顺。那晚盘子不在手边,什么都没刷,产出的是两个被纠正过来的认知和一份到实验室再执行的方案。坑主要在两处:固件不是"拷过去"而是现场拼出来的,以及重读是"先设状态再读",我连着理解错了三次。

修一只坏 U 盘那晚:FC3532 + N18,和我对"重读"的三次理解偏差
封面:一只 U 盘电路板连到一张电压阈值分布图,虚线是滑动的读取参考点
图 0:封面,AI 生成示意图(不是实拍)。

7 月 2 日凌晨两点多,我手里其实什么硬件都没有——坏掉的那只 U 盘在实验室。我自己的盘坏了,厂家把他们的官方量产工具发给我,授权我拿去修。当时的原话是:"这是 U 盘厂家发我的官方的软件,授权我使用。因为我的 U 盘坏了。所以需要用这个软件的固件去写入和覆盖……先分析一下这个软件的内容和对应的硬件。"(2026-07-02 02:09)

于是那一晚就是纯分析:盘不在,一个字节都没刷。我和 Claude Code 把这套工具拆开看,旁边又开了一个 Gemini CLI 做同样的事交叉对照。最后把两件事理顺了:一是这套工具到底怎么修盘,以及我"把固件抠出来覆盖过去"的想法为什么走不通;二是既然我其实还想要盘里的数据,NAND 的"重读"到底怎么工作——这一段我连着理解偏了三次,是我自己把 Claude 拽回正轨的。

先把主控认清楚

工具是一芯(FirstChip)的量产工具 MPTools,版本日期 2024-02-21,一个绿色免安装的 Windows GUI(FCMpTools.exe,176 KB)。Login/Login.exe 加 Authkey.dll 是厂家的授权登录,这是厂家正当发给我的授权,正常登录就行,没什么要绕的。

硬件信息是实验室口头转给我的,先说"FC3379 主控配 N18 芯片",几分钟后又更正成"应该是 FC3532"。这个更正很关键:工具的 code/ 目录下只有 3532 / 3532AB / 3532BB / 3552 / 3552DC / 3562AA 这几个主控文件夹,全文件名搜不到任何 3379,而 FC3532 这套工具完全支持。所以实验室后来给的 FC3532 是对的。

N18 的固件只存在于两个文件夹里——3532AB/ 和 3552/——而且我比对过,这两处的那组 N18 文件逐字节相同。一颗 FC3532 + N18 真正要用到的,是这么几个:

  • code/3532AB/ 里的 extcode_n18.bin 和 extcode_n18.bin01、extmp_n18.bin、extscan_n18.bin
  • 公用的 extmp_readid.bin
  • 参数库 config/cfgu2.bin(USB2,8.9 MB)和 cfgU3.bin(USB3,5.2 MB)
  • 如果颗粒是 QLC,还有 bin/N18QLC2TLC.lua

我想"把固件拷过去",这条路走不通

我最初的设想是:既然这是老版本工具,就把里面对应 N18 的固件抠出来,覆盖到我那套量产版工具上。Claude 和 Gemini 都把我拦下来了,而且理由一致。

那些 code/<主控>/ 下的 .bin 只有 8190 字节,它们不是能直接写进闪存的"成品固件镜像",而是量产时分阶段灌进主控 SRAM 里跑的小程序:extmp_readid 读颗粒 ID,extscan 扫坏块建坏块表,extcode/extmp 是运行码和成盘码(.bin 和 .bin01 是两个候选变体,不是副本——我拿 extcode_n18.bin 和它的 .bin01 比过,8190 字节里有 5533 个不一样)。

真正留在盘里的那份固件,是量产时现场拼出来的:控制器运行码 + 这颗芯片自己的坏块扫描结果 + cfg 参数库 + 容量和 VID/PID 配置,运行时组装,再写进 NAND。坏块表每颗芯片都不同,所以根本不存在一个可以 dd 直接覆盖的镜像文件。

量产工具修盘的真实模型
图 1:上排是我想当然的"拷过去",行不通;下排是量产实际发生的——固件是现场拼的,不是现成的。

N18QLC2TLC.lua 这个脚本也挺说明问题。它一共十几行,做的事是把 N18 这颗 QLC 的扫描缓冲按页号规律(120 页往后,前段每 4 页、后段每 2 页)给对应字节加 128,等于把 QLC 颗粒降成 TLC 模式来跑——掉点容量,换稳定性和寿命。这类颗粒时序/模式的细节全锁在脚本和那几个 .bin 里,不是明文配置,你照着抄字节是抄不出一个能用的盘的。

所以结论很干脆:只要"把盘修好能用",根本不用手动搞任何东西,把支持 N18 的这套文件喂给量产工具重跑一遍量产就行,主控自己会扫、会拼、会写。代价是量产会彻底清空整盘。

但我其实想要里面的数据

问题在于,量产等于抹掉。而我真正想要的是盘里的数据。这就是另一条路了——修盘和救数据是两件事:修盘重跑量产即可;救数据才需要去读原始颗粒,才会碰到"重读"。

那一晚大部分时间花在了救数据这条线上,因为我想搞清楚 N18 的重读参数怎么拿到。

重读:我连着理解错了三次

我要找的是类似美光那套的设置:SET FEATURES (EFh) + 地址 89h + 4 个参数字节,这是老 ONFI 里定义的标准重读参数。我给的判断是:美光和英特尔用同一种重读命令,N18 只是这套体系里更新的一颗。把 Linux 内核的 nand_micron.c、flash-extractor 论坛、flash-matrix 的博客交叉对一遍,这个判断成立——ONFI_FEATURE_ADDR_READ_RETRY = 0x89,Intel 和 Micron 同属 IMFT 的浮栅 3D NAND,重读机制共用。(这里有个容易混的点:Intel 的厂商码本身也是 0x89,但那是 Read ID 的第一字节,和 feature 地址 0x89 是两回事。)

机制对上了,但我对"流程"连着纠正了 Claude 三次:

第一次,它把顺序讲成了"读失败→带参数重读"。不对。重读是先设状态、再读数据:先用 SET FEATURES 把一组参数写进颗粒内部寄存器,改变读取参考电压,这一步只配置、不出数据;等状态生效了,再发一条普通读命令去读那块地址,这一次读用的才是刚设好的电压。电压状态会一直保持,直到你下次再改或复位。

第二次和第三次是同一条话里说的:"这个前面说的好好的 先设置状态 后读参数 怎么到最后还在问档位 n 和页型 而且这个 89 只是个参照 不是实际的 89h 这个芯片"(2026-07-02 03:16)。意思是:别再把"有几档""分几种页型"当成前提去问,参数的值本来就是逐个扫、测哪组读得最干净来定的;而 89h 只是美光那篇博客里的标准示例,这颗 N18 真实的命令形态以工具里存的那份为准,不该拿 89h 当它的实际地址反复讲。

重读的两步与扫描循环
图 2:A 设状态、B 读数据是分开的两步;自动校准不过是把 A→B 循环着扫,取误码最低的那组。

厂家又发来 Flash Extractor,说"里面能扫出来"

接着厂家发了 Flash_Extractor.exe 过来(18.6 MB,32 位 Windows GUI,FE v6),说"在里面有,可以扫出来"。这台机器上没有读卡器、没有授权,盘也不在,所以我没有运行它,只做了静态分析。

里面确实有 N18 需要的重读能力,只是不以"N18"这个名字存着——grep 搜不到 "N18"。它编进程序里的是按厂商分的重读库:Hynix v1–v8、Micron / Micron_v2 / v3 / v4、Samsung、SanDisk。注意整份程序里没有单独的 Intel 重读库,这正好实锤了前面的判断:英特尔 N18 就是走 Micron 这一套。还能看到 Test_Retry、绘图窗 Plot_Window,以及两种搜索策略 Best_at_Saddle(在两个电压分布的谷底找最佳读取点)和 Continuous。

我当时把机制复述给它听:"这个是 flash-extractor.com 主程序,这里面有 retry 功能,用于重读芯片……包含了常见的芯片准确的重复 set FEATURES 的信息,和后面参数的个数;具体参数的数值是循环测试每一个值看看哪个效果好来确定。"(2026-07-02 02:43)拆包看到的类结构跟这段话一一对得上:profile 负责"怎么发命令"(EFh、参数个数,内置好的),扫描引擎负责"发什么值"(Best-at-Saddle 扫出来)。厂家说的"扫出来"就是 FE 的自动重读校准,不是让我去手填一张数值表。我也没有去逆向抠它那张表——没必要,而且那是它的授权数据。

顺手把 N18 这颗解了

我把料号和 Read ID 一起发过去让它解:MT29F01T2ALCQH1(N18) / 89 D4 0C 32 AA 00。

N18 = 英特尔(IMFT)第一代 64 层 3D QLC,单 die 1 Tbit(128 GB 裸容量),浮栅结构。料号里 MT29F 是美光/IMFT 的 NAND 前缀,01T 是 1 Tbit 密度,Q 是 QLC。Read ID 这几个字节:

字节值含义
① Maker89h厂商码 = Intel(美光是 2Ch)
② DeviceD4h高密度 QLC 器件码
③0Ch0000 1100:每 CE 1 个 die,16 电平 = QLC
④32h页/块/spare 几何(老表对 3D QLC 不准)
⑤AAhplane/块大小(同上,不可直接套老表)
⑥00h保留

第 4、5 字节按老的平面 NAND ID 表能算出页/块大小,但对 3D QLC 不准,真要准确几何得读 ONFI 参数页(命令 ECh)。这也跟工具里的命名对上了:N18/N28/N38 对应 Intel 的 64/96/144 层代次,正好是 extcode_n18/n28/n38.bin 和 N18QLC2TLC / N28QTT / N38BQTT 这几个脚本。

那晚凌晨的落点

救数据这条线我还往下走了一步:把 extcode_n18.bin 丢进 IDA,按 8051 架构打开(选处理器变体那一步的截图见下),导出成 .i64,再通过 ida-pro-mcp 看反汇编,想找 EF/89 那条命令流附近存重读参数的数组。Gemini 那边的判断是:这 4 字节参数是编进 extcode 机器码里的,纯文本搜不到,救数据要逆向它才能挖出来。

IDA 按 8051 打开固件时的处理器变体选择
图 3:把 extcode_n18.bin 当 8051 代码打开时的器件选择对话框,那晚留下的真实截图。

但绕到最后,实际可落地的结论没变,而且更简单:不用手工去解那张表。到实验室之后,先读 N18 的 ONFI 参数页拿到准确几何,再用 FE 的 Micron 自动重读去扫(Best at Saddle,Persistence 关掉别把重读值永久写进颗粒,换片/收尾发一次 FDh 复位),扫出误码最低的读取点,整片读出去交后面重组。如果我要的只是"把盘修好能用",那这一整套都不用碰,直接用量产工具重跑量产。

那晚就停在这儿——认知理顺了,方案列好了,盘不在手边,所以没有任何"刷成功"可报。真要给结论,就一句:修盘和救数据是两条路,而我那天凌晨的大半时间,是在把"重读"这件事从三次理解偏差里拎回正确的样子。

← 上一篇 开机卡一分多钟:一台不许省电的解算工作站,前后剥了四层 下一篇 → 用 Claude Code 驱动 ANSYS Maxwell:轴向磁通电机仿真的两个月