Files
STM32F4-Base/docs/GD5F2GQ5UE_Trap_Records.md
2026-08-27 18:22:44 +08:00

136 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GD5F2GQ5UE 陷阱记录
## Trap 01 — 块擦除地址错误(有效)
**发现时间**2026-07-21
**现象**
`gd5f_block_erase()` 使用 `byte_addr = block × 128KB`(字节地址)作为 D8h 命令的入参,但 GD5F2GQ5UE 要求的是**页地址**`block × 64`)。
只有 block 0 的 byte_addr=0 与 page_addr=0 巧合一致,其余块全部指向了错误的物理块。导致:
- 验证流程从未擦除过大部分块,厂标坏块每次重启都恢复
- 基于错误擦除的实验结论全部无效
**根因**
- `gd5f_block_erase(block_addr)``block_addr × GD5F_BLOCK_SIZE` 计算地址
- 芯片 D8h 命令将 24-bit 地址作为页地址(行地址)解析:`RA<16:6>` 选块,`RA<5:0>` 选页内页
- 对于 block=1发送 `{0xD8, 0x00, 0x02, 0x00}` → 芯片视为 page=512 → 擦除 block=8
- 导致 block 1~7、9~15、17~23…等大量块从未被擦除
**修复**:改用 `page_addr = block_addr × GD5F_PAGES_PER_BLOCK`(块首页地址)
**验证结果**(修复后):
- 全部 2048 块正确擦除,厂标全部清除,重启后 BBT scan 为 0
- ECC 开启时 BBT rescan 正常工作
- ECC 校验码正确生成ECCS=0
- Block 0 无特殊行为
**经验教训**
- D8h 和 13h/10h 都使用 24-bit 行地址,格式一致
- 块擦除不使用 `block × block_size`(字节偏移),而用块首页地址
- 芯片手册的 memory mapping 必须严格遵守
## Trap 02 — 测试缓冲越界导致跨页比对误判(有效)
**发现时间**2026-08-26
**现象**
`gd5f_test_task.c``s_wbuf` / `s_rbuf` 按单页大小定义:
```c
static uint8_t s_wbuf[GD5F_PAGE_SIZE]; /* 2048 字节 */
static uint8_t s_rbuf[GD5F_PAGE_SIZE]; /* 2048 字节 */
```
TC-GD5F-302 跨页写读用 `gd5f2gq5ue_write(base + 1000, s_wbuf, 3000)` /
`read(..., s_rbuf, 3000)`。驱动实际把 3000 字节正确写入了 NAND但测试缓冲只有
2048 字节,发生**数组越界**
- 前 2048 字节写入合法区page0 全 + page1 前 1000 字节)→ 比对正确;
- page1 剩余 952 字节被写到 `s_rbuf[2048..2999]`(越界),落入相邻内存,**丢失**
- 比对时读 `s_rbuf[2048..2999]` 为越界垃圾 → 误判 `cross-page MISMATCH`
**根因**
测试缓冲未覆盖实际最大读写长度(跨页场景超过单页 2048 字节)。
**修复**
将缓冲放大到 ≥ 最大读写长度(如 `GD5F_PAGE_SIZE * 2`,即 4096
```c
static uint8_t s_wbuf[GD5F_PAGE_SIZE * 2];
static uint8_t s_rbuf[GD5F_PAGE_SIZE * 2];
```
**验证结果**
缓冲放大后 TC-GD5F-302 一次通过,不再误判。
**经验教训**
- 任何“跨页 / 大于单页”的读写测试,缓冲必须按**实际长度上限**而非单页大小分配
- 越界写会污染相邻全局变量,可能引起其它用例莫名失败,定位时优先怀疑缓冲尺寸
## Trap 03 — 驱动读写擦缺越界检查(有效 / 健壮性缺口)
**发现时间**2026-08-26
**现象**
TC-GD5F-1001 用 `offset = GD5F_TOTAL_SIZE`(恰好超出末尾 1 字节)做 read/write
期望驱动拒绝(返回错误),但 `gd5f2gq5ue_read` / `write` / `erase` 原实现**无任何边界校验**
直接计算 `page_addr = offset / PAGE_SIZE` 后继续操作,返回 `GD5F_OK` → 测试 FAIL。
同时这也意味着正常调用若传入越界参数,会静默访问到回绕后的非法页。
**根因**
`gd5f2gq5ue_read` / `write` / `erase` 入口未校验 `offset` / `size` 是否在
`[0, GD5F_TOTAL_SIZE]` 容量范围内。
**修复**
在三个函数入口统一加边界检查FTL/diskio 均在容量内访问,不受影响):
```c
if (offset < 0 || (unsigned long)offset + size > (unsigned long)GD5F_TOTAL_SIZE) {
return GD5F_ERROR;
}
```
`erase` 在原有的块对齐检查之后、循环之前加同一判断即可。
**验证结果**
- TC-GD5F-1001 read/write 越界均被拒绝ret=-1测试 PASS
- TC-GD5F-1002 size=0 仍返回 `GD5F_OK`offset 合法且 size=0 不越界),符合预期
- 该检查还顺带逮到 Trap 04 的测试越界擦除(见下)
**经验教训**
- 面向字节偏移的裸 NAND 接口必须做容量边界检查,调用方传错参数时尽早失败
- 无越界检查的驱动容易“静默回绕”,问题极难定位
## Trap 04 — gd5f_find_run 返回语义与多块擦除窗口错位(测试 bug
**发现时间**2026-08-26
**现象**
TC-GD5F-402 多块擦除(`gd5f_find_run(3)` 后擦 3 块)返回 `ret=-1`
经 Trap 03 的边界检查定位:实际要擦的块超出了设备末尾。
**根因**
`gd5f_find_run(n)` 原实现返回的是**连续好块的末尾块号** `top`
(校验 `top, top-1, ..., top-(n-1)` 共 n 块),但调用方把返回值当作**起始块号**使用:
```c
base3 = (long)blk3 * GD5F_BLOCK_SIZE;
gd5f2gq5ue_erase(base3, 3 * GD5F_BLOCK_SIZE); /* 实际擦 blk3, blk3+1, blk3+2 */
```
`gd5f_find_run(3)` 返回的末尾块贴到设备末尾(例如 2047即块 2045/2046/2047 为好块)
时,调用方实际要擦 `2047, 2048, 2049`,块 2048/2049 越界。
`n=1` 时首尾块号相同所以不暴露,仅 `n>1` 暴露。
**修复**
统一让 `gd5f_find_run` 返回**起始块号**,与 `n=1` 的用法一致,并仍避开块 0
```c
if (ok) {
return top - (uint32_t)(n - 1); /* 返回连续好块的起始块号 */
}
```
循环条件保持 `top >= (uint32_t)(n - 1) + 1`,保证起始块 ≥ 1。
**验证结果**
修复后 TC-GD5F-402 多块擦除ret=0及“擦后全 0xFF”均 PASS
全套用例最终 60/60 PASSED。
**经验教训**
- 返回“连续区间”的辅助函数,其返回值是起点还是终点必须在注释/命名中明确,
调用方与实现必须一致
- 这类错位 bug 往往只在“区间贴到设备边界”时才触发,正常情况能过,建议测试覆盖边界块