From b5dd94b83470d8b9459eda154b99531c95fbaf14 Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Mon, 21 Sep 2026 03:32:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AD=98=E5=82=A8=E5=A5=97=E4=BB=B6=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=85=A8=E7=89=87=E6=93=A6=E9=99=A4=E7=BB=B4=E6=8A=A4?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E6=81=A2=E5=A4=8D=E5=AE=B9=E9=87=8F=EF=BC=8C?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E8=AE=A2=E6=AD=A3=E5=AE=B9=E9=87=8F=E6=BB=A1?= =?UTF-8?q?=E5=80=BC=E4=B8=8E=E6=81=A2=E5=A4=8D=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/内存管理/内存内容分配策略.md | 2 +- docs/测试说明/GD5F2GQ5UE_Test_Guide.md | 27 ++++++++----- test/storage_test.h | 10 +++++ test/storage_test_task.c | 56 +++++++++++++++++++++++++- 4 files changed, 81 insertions(+), 14 deletions(-) diff --git a/docs/内存管理/内存内容分配策略.md b/docs/内存管理/内存内容分配策略.md index 0402fe8e..4c09e9f8 100644 --- a/docs/内存管理/内存内容分配策略.md +++ b/docs/内存管理/内存内容分配策略.md @@ -128,7 +128,7 @@ LVGL 集合明细(均在 SRAM):LVGL 池 40,960B(`lv_mem_core_builtin.o` 3. 存储套件(`test_config.h` → `TEST_SUITE_STORAGE`):只读模式实测 **3/3 PASSED**(破坏性关,卷内容不变);开启 `ENABLE_DESTRUCTIVE_TESTS` 后为全量集成用例(2026-09-20 实测 **20/20 PASSED**,含 TC-STO-01/02/03/05/06) 4. GD5F 套件(`TEST_SUITE_GD5F`):只读模式实测 **16/16 PASSED**(含只读的守卫负路径 TC-GD5F-704);开启 `ENABLE_DESTRUCTIVE_TESTS` 后 **68/68 PASSED**,并确认日志出现 2 条守卫负路径 `[ERR]`(TC-GD5F-704/705)——破坏性模式运行须放宽 Forbidden(`--forbidden "FAIL;HardFault"`) 5. 恢复跑(`ENABLE_STORAGE_RECOVERY_TESTS`):期望 **3/3 PASSED** -6. **破坏性用例默认关闭**(见 `test_config.h` 的 `ENABLE_DESTRUCTIVE_TESTS`):写/擦 NAND、格式化、坏块注入与 FatFS 写类用例只在首次上电/产线首启或明确需要时开启——2026-09-21 实测一轮破坏性 GD5F 运行即消耗一个块(容量 95248 → 95200,TC-STO-04 恢复不回来);日常回归请保持只读模式 +6. **破坏性用例默认关闭**(见 `test_config.h` 的 `ENABLE_DESTRUCTIVE_TESTS`):写/擦 NAND、格式化、坏块注入与 FatFS 写类用例只在首次上电/产线首启或明确需要时开启——2026-09-21 实测一轮破坏性 GD5F 运行即让 dhara 多记一个坏块(容量 95248 → 95200,且该计数持久化在 dhara journal checkpoint 头里,`nand_ftl_format` 清不掉);日常回归请保持只读模式。容量满值 = **96064 pages(187 MB)**,被扣掉的容量可用 `ENABLE_STORAGE_RECOVERY_TESTS` + `STORAGE_RECOVERY_FULL_WIPE`(全片擦除 + 重建 BBT)恢复(实测 95200 → 96064 ✓) 通过全部关卡后:更新 §6 台账、`AGENTS.md` 栈表、`.sct` 头注释,并把本次裁决补入 §5。 diff --git a/docs/测试说明/GD5F2GQ5UE_Test_Guide.md b/docs/测试说明/GD5F2GQ5UE_Test_Guide.md index 9396df3d..06929f61 100644 --- a/docs/测试说明/GD5F2GQ5UE_Test_Guide.md +++ b/docs/测试说明/GD5F2GQ5UE_Test_Guide.md @@ -60,7 +60,8 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10` > 控制所有**会改变设备持久状态**的用例——写/擦 NAND、`nand_ftl_format`、FatFS 建文件写文件、 > 向 BBT 持久化坏块标记(永久减少可用容量)。关闭时为**只读模式**,可随时在在用设备上跑; > 打开后才编译并运行 PHASE3~9,以及 PHASE2 的 TC-206/207、PHASE10 的 TC-1003/1004。 -> 依据:2026-09-21 实测一轮破坏性 GD5F 运行即消耗一个块(容量 95248 → 95200,TC-STO-04 恢复不回来), +> 依据:2026-09-21 实测一轮破坏性 GD5F 运行即让 dhara 多记一个坏块(容量 95248 → 95200; +> dhara 把该计数持久化在 journal checkpoint 头里,普通恢复模式清不掉——见下文容量恢复说明), > 故破坏性用例只在**产品首次上电/产线首启**或明确需要时开启。 `test/test_config.h` 配置示例(三选一,互斥,多选触发 `#error`): @@ -510,16 +511,20 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10` | **覆盖原则** | DMA 可达性守卫(写方向);堆缓冲禁入 DMA 的运行时强制(内存分配策略 R3) | > ⚠ **卷破坏警告(仅 `ENABLE_DESTRUCTIVE_TESTS` 打开时)**:阶段 8 会调用 `nand_ftl_format()` -> 清空 dhara map,阶段 9 会写入文件—— -> 整轮 GD5F 套件(含 Phase 8/9)运行后卷数据即失效,且大写入可能使 dhara 把若干块记为 -> 运行期坏块(2026-09-21 实测:一次整轮运行容量 95248 → 95200,日志见 -> `[ERR][NAND_FTL] program verify: data mismatch, blk 305`,该块由 dhara 自行隔离,测试仍 68/68 通过)。 -> 需要恢复**卷/BBT 干净态**时,启用 `ENABLE_STORAGE_RECOVERY_TESTS` 跑一次 STORAGE 套件的 -> TC-STO-04(重建 BBT + 重新格式化)。 -> **注意:TC-STO-04 不恢复容量**——2026-09-21 实测恢复后容量仍为 95200,且断电重扫、 -> BBT 重建、dhara 重新格式化后都保持 95200(dhara 每次扫描都会再次排除该块)。 -> 即被排除的块是**真实运行期坏块**,不应擦除复用(NAND 惯例:程序校验失败的块永久弃用); -> 当前容量基线以 **95200 pages(185 MB)** 为准。 +> 清空 dhara map,阶段 9 会写入文件——整轮运行后卷数据即失效;大写入还可能使 dhara 多记一个 +> 坏块(2026-09-21 实测:一次整轮运行容量 95248 → 95200,日志见 +> `[ERR][NAND_FTL] program verify: data mismatch, blk 305`,该块被 dhara 隔离,测试仍 68/68 通过)。 +> +> **容量记账与恢复(2026-09-21 读码 + 台架实证)**: +> - 健康满容量 = **96064 pages(187 MB)**(`No valid map found, creating fresh` 分支下的满值)。 +> - 容量随 dhara 计到的坏块数递减,且该计数**持久化在 journal checkpoint 头里** +> (`journal.c` `hdr_set_bb_current/bb_last`);`dhara_journal_clear()` 只做 +> `bb_last = bb_current`(**不归零**)——所以 `nand_ftl_format()`(TC-STO-04 普通恢复) +> **清不掉被扣掉的容量**,断电重扫也一样。 +> - 恢复满容量:启用 `ENABLE_STORAGE_RECOVERY_TESTS` **并叠加** `STORAGE_RECOVERY_FULL_WIPE` +> 跑一次 STORAGE 套件(擦净 dhara 可见区 2044 块 + 重建 BBT),随后断电重启—— +> `dhara_map_resume` 失败 → 走 `dhara_map_clear` 全新初始化(bb_last = bb_current = 0)→ 容量回满。 +> 实测 2026-09-21:95200 → **96064** ✓(代价:卷内容全失,启动时 FatFs 自动重建)。 ## 9. 阶段 8:FTL 层(nand_ftl) diff --git a/test/storage_test.h b/test/storage_test.h index 756d6e00..64985994 100644 --- a/test/storage_test.h +++ b/test/storage_test.h @@ -50,6 +50,16 @@ void storage_test_run(void); * 恢复完成后建议重新注释并编译正常构建。 */ //#define ENABLE_STORAGE_RECOVERY_TESTS /* 台架已跑过一次恢复(2026-09-20 BBT 回出厂态),保持注释 */ +/* 恢复模式的扩展(默认关闭,需与上面 ENABLE_STORAGE_RECOVERY_TESTS 同时打开): + * 把 dhara 可见区**整片擦净**(连 journal checkpoint 一起),用于**把被扣掉的容量恢复回来**。 + * 原理(2026-09-21 读码 + 台架实证):dhara 把坏块计数持久化在 checkpoint 头里 + * (journal.c `hdr_set_bb_current/bb_last`),而 `dhara_journal_clear()` 只是 + * `bb_last = bb_current`(**不归零**)——所以 `nand_ftl_format()` 恢复不了容量(95200 卡住); + * 只有让下次启动 `dhara_map_resume` 失败、走 `dhara_map_clear` 的**全新初始化**分支 + * (此时 bb_last = bb_current = 0)才能回满。2026-09-21 台架实测:95200 → **96064**(健康满值 ✓)。 + * 代价:卷内容全失(启动时 FatFs 自动重建)、约 2044 次块擦除(数十秒)。 */ +//#define STORAGE_RECOVERY_FULL_WIPE + #ifdef __cplusplus } #endif diff --git a/test/storage_test_task.c b/test/storage_test_task.c index 131ec9e0..dccef937 100644 --- a/test/storage_test_task.c +++ b/test/storage_test_task.c @@ -543,19 +543,66 @@ void storage_test_run(void) } #ifdef ENABLE_STORAGE_RECOVERY_TESTS -/* TC-STO-04: 重建 BBT + 重新格式化(恢复 TC-STO-03 注入的坏块) + +#ifdef STORAGE_RECOVERY_FULL_WIPE +/* + * 函数功能:擦净 dhara 可见区全部块(容量恢复用) + * 入口参数:无 + * 返回值:无 + * 限定条件:SPI/驱动已初始化;调用期间无其它存储访问(测试构建下单写者) + * 函数说明:逐块擦除 [0, gd5f_get_usable_blocks()),跳过 BBT 记录的坏块, + * 保留块池(BBT 存储区)不动。擦净后 journal checkpoint 不复存在, + * 下次启动 dhara_map_resume 失败 → dhara_map_clear 全新初始化 + * (bb_last = bb_current = 0)→ 容量回满。 + * 注意:擦净后**不能**再调 nand_ftl_format()(会把内存中仍带旧坏块 + * 计数的 journal 状态重新落盘,容量又被扣掉)。 + */ +static void storage_test_wipe_visible(void) +{ + uint32_t usable = gd5f_get_usable_blocks(); + uint32_t done = 0; + uint32_t skipped = 0; + uint32_t b; + + for (b = 0; b < usable; b++) { + if (gd5f2gq5ue_is_block_bad(b) != 0) { + skipped++; + continue; + } + if (gd5f_block_erase(b) == GD5F_OK) { + done++; + } else { + DBG_ERROR(" block %lu erase failed", (unsigned long)b); + } + if ((b % 256U) == 0U) { + DBG_INFO(" wipe progress: %lu/%lu", (unsigned long)b, (unsigned long)usable); + } + } + + DBG_INFO(" wiped %lu blocks (%lu skipped as bad, %lu visible)", + (unsigned long)done, (unsigned long)skipped, (unsigned long)usable); + STORAGE_TEST_CHECK(done > 0U, "TC-STO-04 full wipe (%lu blocks erased)", + (unsigned long)done); +} +#endif /* STORAGE_RECOVERY_FULL_WIPE */ + +/* TC-STO-04: 维护模式(恢复 = 重建 BBT + 重新格式化;叠加全片擦除 = 容量恢复) * 仅在启用 ENABLE_STORAGE_RECOVERY_TESTS 时编译运行;运行一次即可把设备 * 恢复到干净出厂态(清除运行时注入坏块并清空 dhara map)。 */ static void storage_test_recover(void) { - DBG_INFO("=== Storage Test: TC-STO-04 BBT rebuild + format (recovery) ==="); + DBG_INFO("=== Storage Test: TC-STO-04 maintenance (recovery / full wipe) ==="); int r = gd5f2gq5ue_bbt_rebuild(); STORAGE_TEST_CHECK(r == GD5F_OK, "TC-STO-04 bbt rebuild"); +#ifdef STORAGE_RECOVERY_FULL_WIPE + storage_test_wipe_visible(); +#else nand_ftl_format(); STORAGE_TEST_CHECK(1, "TC-STO-04 nand_ftl_format done"); +#endif uint8_t fb[GD5F_TOTAL_BLOCKS / 8]; uint32_t ver = 0; @@ -565,6 +612,11 @@ static void storage_test_recover(void) STORAGE_TEST_CHECK(0, "TC-STO-04 dump_flash failed"); } +#ifdef STORAGE_RECOVERY_FULL_WIPE + DBG_INFO("TC-STO-04 full wipe complete; power-cycle to rebuild fresh " + "(capacity expected back to full)"); +#else DBG_INFO("TC-STO-04 recovery complete; recommend power-cycle to re-init cleanly"); +#endif } #endif