NVMe-eMMC Bridge 芯片固件开发(六):SSD 通用概念与实现

概述

本文介绍 SSD 主控固件开发中的核心概念,结合 NVMe-eMMC Bridge 项目的实际代码实现,涵盖:

  • SMART 健康信息监控:寿命估计、读写统计、温度监控
  • 磨损均衡(Wear Leveling):eMMC 内置 FTL 与寿命预警
  • Disk Model Name 动态控制:运行时组装设备名称
  • Namespace 管理:多命名空间动态配置
  • 固件更新机制:NVMe Firmware Download/Commit 与 eMMC FFU

1. SMART 健康信息机制

1.1 SMART 信息架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
┌─────────────────────────────────────────────────────────────────────┐
│ SMART Information Framework │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌──────────────────┐ ┌───────────────┐ │
│ │ NVMe Host │───▶│ SMART Get Log │───▶│ Log Page │ │
│ │ (Get Log 02h) │ │ Page 02h │ │ Response │ │
│ └─────────────────┘ └──────────────────┘ └───────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ smart_data (RAM) │ │
│ │ ┌─────────────────┬─────────────────┬─────────────────────┐ │ │
│ │ │ critical_warning│ percentage_used │ power_on_hours │ │ │
│ │ │ temperature │ data_units_read │ data_units_written │ │ │
│ │ │ power_cycles │ host_read_cmds │ host_write_cmds │ │ │
│ │ └─────────────────┴─────────────────┴─────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ │ Timer更新 │ IO操作更新 │ 初始化读取 │
│ ▼ ▼ ▼ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────────┐ │
│ │smart_info_ │ │smart_info_ │ │smart_info_ │ │
│ │update_by_timer │ │update_by_ops │ │init │ │
│ └────────────────┘ └────────────────┘ └────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ eMMC Reserved Block Storage │ │
│ │ (掉电持久化 SMART 数据) │ │
│ └────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘

1.2 SMART 数据结构定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// smart_info.h - NVMe SMART 健康信息数据结构
typedef struct {
u32 available_spare:8; // 可用备用空间百分比
u32 available_space_threshold:8; // 备用空间阈值
u32 critical_warning_and_temperature; // 关键警告 + 复合温度
u32 percentage_used; // 寿命使用百分比

// 128-bit 计数器(支持超大容量统计)
u64 data_units_read_low; // 读取数据单元(低64位)
u64 data_units_read_high;
u64 data_units_written_low; // 写入数据单元
u64 data_units_written_high;
u64 host_read_commands_low; // 主机读命令计数
u64 host_read_commands_high;
u64 host_write_commands_low; // 主机写命令计数
u64 host_write_commands_high;
u64 controller_busy_time_low; // 控制器忙时间(分钟)
u64 controller_busy_time_high;
u64 power_cycles_low; // 上电次数
u64 power_cycles_high;
u64 power_on_hours_low; // 上电小时数
u64 power_on_hours_high;
u64 unsafe_shutdowns_low; // 非安全关机次数
u64 unsafe_shutdowns_high;
u64 media_and_data_integrity_errors_low; // 介质错误
u64 media_and_data_integrity_errors_high;
u64 number_of_error_information_log_entries_low;
u64 number_of_error_information_log_entries_high;
u32 warning_composite_temperature_time;
} smart_health_info_data_t;

1.3 SMART 数据更新流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
┌─────────────────────────────────────────────────────────────────┐
│ SMART 数据更新机制 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Timer 中断触发更新 │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────────┐ │ │
│ │ │ 1小时定时 │───▶│power_on_ │───▶│ 运行时间 +1 │ │ │
│ │ │ │ │hours +1 │ │ │ │ │
│ │ └───────────┘ └───────────┘ └───────────────┘ │ │
│ │ │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────────┐ │ │
│ │ │ 1分钟定时 │───▶│controller_│───▶│ 忙时间累计 │ │ │
│ │ │ (忙状态) │ │busy +1 │ │ │ │ │
│ │ └───────────┘ └───────────┘ └───────────────┘ │ │
│ │ │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────────┐ │ │
│ │ │ 1小时定时 │───▶│ Writeback │───▶│ 持久化到eMMC │ │ │
│ │ │ │ │ to eMMC │ │ │ │ │
│ │ └───────────┘ └───────────┘ └───────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ IO 操作触发更新 │ │
│ │ │ │
│ │ NVMe Read ──▶ data_units_read += block_count │ │
│ │ host_read_commands++ │ │
│ │ │ │
│ │ NVMe Write ─▶ data_units_written += block_count │ │
│ │ host_write_commands++ │ │
│ │ │ │
│ │ Power On ───▶ power_cycles++ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

1.4 核心实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// smart_info.c - SMART 信息初始化(从 eMMC 加载持久化数据)
void smart_info_init(smart_rw_emmc_p smart_rw, smart_health_info_data_p smart_data)
{
smart_rw->rw_opt = READ_EMMC;
smart_rw->rw_size = EMMC_BLOCK_SIZE;
smart_rw->addr_ram = smart_rw->temp_buffer;

// 选择 eMMC 保留块地址(根据配置选择不同偏移)
if (fw_param.emmc_resv_blk_mod)
smart_rw->addr_offset = EMMC_RESERVE_BLOCK4_OFFSET;
else
smart_rw->addr_offset = EMMC_RESERVE_BLOCK2_OFFSET;

// 从 eMMC 读取 SMART 数据
smart_info_emmc_rw(smart_rw, smart_data);
}

// Timer 触发的 SMART 更新
void smart_info_update_by_timer(timer_flags_p timer_flags,
smart_rw_emmc_p smart_rw,
smart_health_info_data_p smart_data)
{
// 定时写回 eMMC(1小时周期)
if (timer_flags->smart_info.smartinfo_update_emmc_flag == 1) {
timer_flags->smart_info.smartinfo_update_emmc_flag = 0;
smart_info_writeback(smart_rw, smart_data);
}
// 运行小时数更新(1小时周期)
if (timer_flags->smart_info.smartinfo_power_on_hour_flag == 1) {
timer_flags->smart_info.smartinfo_power_on_hour_flag = 0;
smart_data->power_on_hours_low += 1;
}
// 忙时间更新(1分钟周期,在控制器忙时)
if (timer_flags->smart_info.smartinfo_busy_time_flag == 1) {
timer_flags->smart_info.smartinfo_busy_time_flag = 0;
smart_data->controller_busy_time_low += 1;
}
}

// IO 操作触发的 SMART 更新
void smart_info_update_by_ops(u8 info_id, u16 cnt, smart_health_info_data_p smart_data)
{
switch (info_id) {
case ID_DATA_UNIT_READ:
smart_data->data_units_read_low += cnt; // 单位:1000 blocks
break;
case ID_DATA_UNIT_WRITE:
smart_data->data_units_written_low += cnt;
break;
case ID_HOST_READ_CMD:
smart_data->host_read_commands_low += cnt;
break;
case ID_HOST_WRITE_CMD:
smart_data->host_write_commands_low += cnt;
break;
case ID_POWER_CYCLE:
smart_data->power_cycles_low += cnt;
break;
case ID_CRITICAL_WARN:
smart_data->critical_warning_and_temperature |= cnt << 2;
break;
case ID_PERCENTAGE_USED:
smart_data->percentage_used = cnt << 8;
break;
case ID_MEDIA_DATA_ERROR:
smart_data->media_and_data_integrity_errors_low += cnt;
break;
}
}

2. 磨损均衡与寿命监控

2.1 磨损均衡概述

BayBridge 固件实现了双 eMMC 软件磨损均衡 (Software Wear-Leveling, SWEAR) 功能。当两个 eMMC 卡容量不同时,NVMe Host 看到的是合并后的总容量,需要软件层面进行磨损均衡。

编译开关

1
2
3
4
5
6
7
8
9
10
// BB_MMC_SWEAR_ENABLE: 软件磨损均衡使能
// 配置文件目录: config/defs/
// - WL_on: 启用 SWEAR
// - WL_off: 禁用 SWEAR

#if BB_MMC_SWEAR_ENABLE
// SWEAR 模式: 交替写入两个 eMMC
#else
// 普通模式: 直接地址映射
#endif

2.2 SWEAR 核心概念

Particle 概念

1
2
3
4
5
6
// read_write.h - Particle 大小定义
#define WL_M (1024 * WL_K) // 1MB (单位: 块)
#define WL_K 1024 // 1KB (单位: 块)
#define PARTCIAL_SIZE (u32)((1 << (fw_param.particle_size_cfg)) * (4 * WL_K))
// particle_size_cfg = 0xA 时:
// PARTCIAL_SIZE = 2^10 * 4KB = 4MB

逻辑空间划分

当两个 eMMC 容量不同时,NVMe LBA 空间被划分为三个区域:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
┌────────────────────────────────────────────────────────────────────┐
│ SWEAR 逻辑空间划分 (eMMC0 = 32GB, eMMC1 = 64GB) │
├────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Section 1: 交替区域 │ │
│ │ ┌────────┬────────┬────────┬────────┬────────┐ │ │
│ │ │Part 0 │Part 1 │Part 2 │Part 3 │... │ │ │
│ │ │ eMMC0 │ eMMC1 │ eMMC0 │ eMMC1 │ │ │ │
│ │ │ 4MB │ 4MB │ 4MB │ 4MB │ │ │ │
│ │ └────────┴────────┴────────┴────────┴────────┘ │ │
│ │ │ │
│ │ 起始 100MB 和末尾 40MB 保留给固件存储 │ │
│ │ (前 100MB,后 40MB 固定写入 eMMC0) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Section 2: 尾部区域 │ │
│ │ │ │
│ │ 写入 eMMC1 的尾部区域 (容量差部分) │ │
│ │ 大小 = eMMC1_capacity - eMMC0_capacity │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────┘

2.3 容量解析算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// read_write.c - emmc_capacity_parse()
// 根据两个 eMMC 的实际容量计算分区大小

void emmc_capacity_parse(chip_data_info_t *chip_data_info)
{
// 1. 确定大小容量卡
if(emmc0_cap < emmc1_cap) {
chip_data_info->min_cap = emmc0_cap; // 小容量
chip_data_info->max_cap = emmc1_cap; // 大容量
chip_data_info->big_cap_chip = 1; // eMMC1 是大容量卡
}

// 2. 计算 particle 数量
chip_data_info->partcial_count = min_cap / PARTCIAL_SIZE;
chip_data_info->last_part_size = min_cap % PARTCIAL_SIZE;

// 3. 计算区域大小
// Section 1: 所有 particles (交替区域) = partcial_count * PARTCIAL_SIZE * 2
chip_data_info->section1_size = chip_data_info->partcial_count * PARTCIAL_SIZE * 2;

// Section 2: 小卡尾部的双份 (用于交替) = last_part_size * 2
chip_data_info->section2_size = chip_data_info->last_part_size * 2;

// Section 3: 大卡的额外容量
chip_data_info->section3_size = max_cap - min_cap;
}

2.4 地址转换算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// read_write.c - calculate_start_address()
// 将 NVMe LBA 地址转换为实际的 eMMC 物理地址

void calculate_start_address(u32 address, chip_data_info_t *chip_data_info)
{
u32 head_part_count = address / PARTCIAL_SIZE; // 起始 particle 编号
u32 head_part_offset = address % PARTCIAL_SIZE; // 在 particle 内的偏移

// 关键: 奇数 particle 写入 eMMC1,偶数 particle 写入 eMMC0
if((head_part_count % 2) == 0) {
chip_data_info->start_chip = 0; // eMMC0
// 实际地址 = (particle编号/2) * PARTCIAL_SIZE + 偏移
chip_data_info->emmc[0].addr = (head_part_count/2) * PARTCIAL_SIZE + head_part_offset;
} else {
chip_data_info->start_chip = 1; // eMMC1
chip_data_info->emmc[1].addr = ((head_part_count-1)/2) * PARTCIAL_SIZE + head_part_offset;
}
}

2.5 跨 Particle 写操作处理

当一个写操作跨越多个 particles 时,需要拆分为多个 eMMC 命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// calculate_loop_count() - 计算需要的循环次数

typedef enum {
SEC1_SEC1 = 0, // 同区同卡
SEC1_SEC2_EMMC0, // Section1 → Section2, eMMC0
SEC1_SEC2_EMMC1, // Section1 → Section2, eMMC1
SEC1_SEC3, // Section1 → Section3
SEC2_EMMC0_SEC2_EMMC0, // Section2 同卡连续
SEC2_EMMC0_SEC2_EMMC1, // Section2 → eMMC1
SEC2_EMMC1_SEC2_EMMC1, // Section2 同卡连续
SEC2_EMMC0_SEC3, // Section2 → Section3
SEC1_SEC2_SEC3, // Section1 → Section2 → Section3
SEC2_EMMC1_SEC3, // Section2 → Section3
SEC3_SEC3, // Section3 同区
} data_cover_type;

2.6 保留区域处理

1
2
3
4
5
6
7
8
// 起始 100MB 和末尾 40MB 保留给固件使用,固定写入 eMMC0
if((address < 100 * WL_M)
|| (address > section1_size - 40 * WL_M && address < section1_size + section2_size + 40 * WL_M)
|| address > (section1_size + section2_size + section3_size - 40 * WL_M))
{
// 这些地址固定写入 eMMC0
card_slot = 0;
}

2.7 SWEAR 架构图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
┌────────────────────────────────────────────────────────────────────┐
│ SWEAR 完整架构图 │
├────────────────────────────────────────────────────────────────────┤
│ │
│ NVMe Host │
│ LBA: 0x0000_0000 ──────────────────────────────────────────► │
│ │
│ BayBridge Firmware (BB_MMC_SWEAR_ENABLE) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ emmc_capacity_parse() │ │ │
│ │ │ • 确定大小容量卡 │ │ │
│ │ │ • 计算 Section 1/2/3 大小 │ │ │
│ │ │ • 计算 Particle 数量 │ │ │
│ │ └────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ calculate_start_address() │ │ │
│ │ │ • 计算起始 Particle 编号 │ │ │
│ │ │ • 奇数 → eMMC1, 偶数 → eMMC0 │ │ │
│ │ │ • 转换 LBA → eMMC 物理地址 │ │ │
│ │ └────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ calculate_loop_count() │ │ │
│ │ │ • 检测跨 Particle 边界 │ │ │
│ │ │ • 确定需要的循环次数 │ │ │
│ │ │ • 拆分命令: eMMC0 → eMMC1 → eMMC0 → ... │ │ │
│ │ └────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ └──────────────────────────┼──────────────────────────────┘ │
│ │ │
│ ┌───────────────┴───────────────┐ │
│ ▼ ▼ │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ eMMC 0 │ │ eMMC 1 │ │
│ │ │ │ │ │
│ │ [Part 0][Part 2] │ │ [Part 1][Part 3] │ │
│ │ [Part 4][Part 6] │ │ [Part 5][Part 7] │ │
│ │ ... │ │ ... │ │
│ │ │ │ │ │
│ │ 尾部保留区 │ │ 额外容量区 │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────┘

2.8 固件配置参数

1
2
3
4
5
6
7
8
9
// flash_header_parameter.cfg - SWEAR 相关配置

// Particle 大小: (2 ^ particle_size_cfg) * 4KB
// 默认 0xA = 4MB
particle_size_cfg:0xA

// WL_on 配置目录示例:
// config/defs/*_WL_on.def
// 这些配置启用了 SWEAR 功能

2.9 eMMC 内部磨损均衡

除了固件层面的 SWEAR,eMMC 芯片内部也实现了硬件磨损均衡:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
┌────────────────────────────────────────────────────────────────────┐
│ 完整磨损均衡架构 │
├────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ BayBridge Firmware SWEAR │ │
│ │ │ │
│ │ • LBA → eMMC 交替映射 (软件层) │ │
│ │ • 跨 Particle 边界处理 │ │
│ │ • 双卡容量差异处理 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ eMMC 内部 FTL (硬件层) │ │
│ │ │ │
│ │ • 逻辑块地址 → 物理块地址映射 │ │
│ │ • 动态磨损均衡 (频繁访问块 → 少访问块) │ │
│ │ • 静态磨损均衡 (长期不变块 → 高磨损块) │ │
│ │ • 坏块管理 + 备用块替换 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ NAND Flash 介质 │ │
│ │ │ │
│ │ Block 0 Block 1 Block 2 ... Block N │ │
│ │ [PE:120] [PE:45] [PE:200] [PE:180] │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ PE = Program/Erase 擦写次数 │
└────────────────────────────────────────────────────────────────────┘

2.10 寿命信息获取

从 eMMC EXT_CSD 寄存器读取寿命估计值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// emmc_support_functions.c - eMMC 寿命查询
void emmc_features_query(u8 card_slot)
{
// 初始化温度信息
init_capability_temperature(card_slot);

// 检查 PRE_EOL(预警寿命结束)
// EXT_CSD[267]: PRE_EOL_INFO
// 0x00 = 未定义
// 0x01 = 正常
// 0x02 = 消耗警告(80%)
// 0x03 = 紧急(90%+)
if (card_info.ext_csd[267] == 0x03 ||
card_info.ext_csd[268] == 0x0B ||
card_info.ext_csd[269] == 0x0B) {
card_info.crit_warn[card_slot] = 1; // 设置关键警告
}

// DEVICE_LIFE_TIME_EST_TYP_A [268]: SLC 寿命估计
// DEVICE_LIFE_TIME_EST_TYP_B [269]: MLC 寿命估计
// value * 10 = 已使用寿命百分比
u8 emmc_life_used_value = card_info.ext_csd[268] | card_info.ext_csd[269];

// 值范围 0x01~0x0B:
// 0x01 = 0%~10% 已使用
// 0x0B = 100% 已使用(或超过)
card_info.perc_used[card_slot] = 10 * (emmc_life_used_value > 0 ?
emmc_life_used_value - 1 : 1);

// 读取 eMMC 固件版本
fn_memcpy(&card_info.firmware_version[card_slot][0],
&card_info.ext_csd[254], 8);
}

2.11 寿命信息报告到 SMART

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 将 eMMC 寿命映射到 NVMe SMART Percentage Used
void report_percentage_used_to_smart()
{
u8 first_card_id = (card_num == 1) ? 1 : 0;

// 取两张卡中较大的磨损值
u8 max_perc_used = (card_info.perc_used[0] > card_info.perc_used[1]) ?
card_info.perc_used[0] : card_info.perc_used[1];

smart_info_update_by_ops(ID_PERCENTAGE_USED, max_perc_used, &smart_data);

// 如果任一卡有预警,设置 critical warning
if (card_info.crit_warn[0] || card_info.crit_warn[1]) {
smart_info_update_by_ops(ID_CRITICAL_WARN, 1, &smart_data);
}
}

3. Disk Model Name 动态控制

3.1 动态组装架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
┌───────────────────────────────────────────────────────────────────────┐
│ Model Name 动态组装机制 │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ fw_param.model_number_field_enable (位掩码控制) │
│ ┌───┬───┬───┬───┬───┬───┬───┬───┐ │
│ │ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │
│ └───┴───┴───┴───┴───┴───┴───┴───┘ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ └── VEN_NAME (厂商名称) │
│ │ │ │ │ │ │ └────── OEM_NAME (OEM 定制) │
│ │ │ │ │ │ └────────── EMMC_MID (eMMC 制造商) │
│ │ │ │ │ └────────────── EMMC_PNM (eMMC 产品名) │
│ │ │ │ └────────────────── EMMC_FW_VER (eMMC 固件版本) │
│ │ │ └────────────────────── EMMC_CAPACITY (容量) │
│ │ └────────────────────────── POSTFIX (后缀字符串) │
│ └────────────────────────────── Reserved │
│ │
│ 组装示例 (model_number_field_enable = 0x3D): │
│ ┌─────────┬─────────┬─────────┬─────────┬─────────┐ │
│ │ BAYHUB │ Samsung │ HBG4e2 │ 256GB │ SSD │ = 39字符 │
│ │ (VEN) │ (OEM) │ (PNM) │ (CAP) │ (POST) │ │
│ └─────────┴─────────┴─────────┴─────────┴─────────┘ │
│ │
│ NVMe Identify Controller 报告: "BAYHUB Samsung HBG4e2 256GB SSD" │
│ │
└───────────────────────────────────────────────────────────────────────┘

3.2 动态组装实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// system.c - Model Name 动态组装
static void model_name_init()
{
// 方式1:如果配置文件预设了固定 model_number,直接使用
if (*(u32 *)(&fw_param.model_number[0]) != 0) {
fn_memcpy((byte *)BBS_MODEL_NUMBER_ADDR,
(byte *)fw_param.model_number, 40);
return;
}

// 方式2:根据 field_enable 位掩码动态组装
byte mn_str[40] = {0};
mn_field_t mn_field = {0};

// 检查各字段使能位,依次组装
if (assert_mn_field_enable(MN_BIT_ENABLE_MASK_VEN_NAME)) {
// 填充厂商名称: "BAYHUB "
mn_field.ven_len = create_mn_ven_str(mn_str + mn_field.total_len);
mn_field.total_len += mn_field.ven_len;
}

if (assert_mn_field_enable(MN_BIT_ENABLE_MASK_OEM_NAME)) {
// 填充 OEM 定制名称
mn_field.oem_len = create_mn_oem_str(mn_str + mn_field.total_len);
mn_field.total_len += mn_field.oem_len;
}

if (assert_mn_field_enable(MN_BIT_ENABLE_MASK_EMMC_MID)) {
// 填充 eMMC 制造商 ID (从 CID 寄存器读取)
mn_field.emmc_mid_len = create_mn_card_manufactid_str(mn_str + mn_field.total_len);
mn_field.total_len += mn_field.emmc_mid_len;
}

if (assert_mn_field_enable(MN_BIT_ENABLE_MASK_EMMC_PNM)) {
// 填充 eMMC 产品名称 (从 CID 寄存器读取)
mn_field.emmc_pnm_len = create_mn_card_productname_str(mn_str + mn_field.total_len);
mn_field.total_len += mn_field.emmc_pnm_len;
}

if (assert_mn_field_enable(MN_BIT_ENABLE_MASK_EMMC_CAPACITY)) {
// 填充容量字符串: "128GB"、"256GB" 等
mn_field.emmc_capacity_len = create_mn_card_capacity_str(mn_str + mn_field.total_len);
mn_field.total_len += mn_field.emmc_capacity_len;
}

if (assert_mn_field_enable(MN_BIT_ENABLE_MASK_POSTFIX)) {
// 填充后缀: "SSD"、"NVMe" 等
mn_field.postfix_len = create_mn_postfix_str(mn_str + mn_field.total_len);
mn_field.total_len += mn_field.postfix_len;
}

// 溢出检测:NVMe 规范限制 40 字节
if (mn_field.total_len > 40) {
LOG(ERROR, LOG_ERROR_STR, MODEL_NAME_OVERFLOW);
return;
}

// 写入硬件寄存器
fn_memcpy((byte *)BBS_MODEL_NUMBER_ADDR, mn_str, mn_field.total_len);
}

// 辅助函数:从 eMMC CID 寄存器读取制造商名称
static u8 create_mn_card_manufactid_str(byte *str)
{
byte first_card_id = (card_num == 1) ? 1 : 0;
u8 mid = card_info.cid[first_card_id].mid; // Manufacturer ID

// 常见 eMMC 制造商 ID 映射
switch (mid) {
case 0x13: fn_strcpy(str, "Micron "); return 7;
case 0x15: fn_strcpy(str, "Samsung "); return 8;
case 0x45: fn_strcpy(str, "SanDisk "); return 8;
case 0x90: fn_strcpy(str, "Hynix "); return 6;
case 0xFE: fn_strcpy(str, "Toshiba "); return 8;
default: fn_strcpy(str, "Unknown "); return 8;
}
}

4. Namespace 管理

4.1 多命名空间架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
┌────────────────────────────────────────────────────────────────────────┐
│ Namespace 动态配置架构 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Namespace 配置方式 │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ DEFAULT_SINGLE_NS : 两张 eMMC 合并为单命名空间 │ │
│ │ DEFAULT_DUAL_NS : 两张 eMMC 各自独立命名空间 │ │
│ │ DEFAULT_HIDE_NS : 隐藏指定 eMMC 卡 │ │
│ │ DYNAMIC_HIDE_NS : BIOS 运行时动态配置 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ DYNAMIC_HIDE_NS 使用场景: │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ BIOS Stage ┌─────────────────────────────┐ │ │
│ │ │ │ BBS 0x80 寄存器 (Stick Reg) │ │ │
│ │ │ ① 检测双卡容量 │ [7:0] Namespace 配置值 │ │ │
│ │ │ │ 0xAA = 双命名空间 │ │ │
│ │ ▼ │ 0x55 = 单命名空间合并 │ │ │
│ │ ② 决定 Namespace 配置 ────▶│ 0x11 = 隐藏 eMMC0 │ │ │
│ │ │ │ 0x22 = 隐藏 eMMC1 │ │ │
│ │ │ ③ 写入 BBS 0x80 │ 0x00 = 隐藏全部 │ │ │
│ │ │ └─────────────────────────────┘ │ │
│ │ ▼ │ │
│ │ ④ 发送 CC.EN ────▶ FW 读取 BBS 0x80 配置 Namespace │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ⑤ F12 显示磁盘(正确容量) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ OS Stage (Windows/Linux) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ OS 看到正确的 Namespace 配置 │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘

4.2 Namespace 配置实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// namespace.c - Namespace 动态映射
static void namespace_mapping_init()
{
ns_emmc_map.namespace_class = fw_param.namespace_class;
ns_emmc_map.emmc_num = get_card_num();

// 读取 BIOS 设置的寄存器值
ns_emmc_map.bbs_reg_val = (get_reg(BAYBRIDGE_NVME_CONTROLLER_BASE, 0x4C) >> 24) & 0xFF;

switch (ns_emmc_map.emmc_num) {
case 2: // 双卡配置
if (ns_emmc_map.namespace_class == DYNAMIC_HIDE_NS) {
switch (ns_emmc_map.bbs_reg_val) {
case ALL_CARD_AS_SINGLE_NS: // 0x55
ns_emmc_map.case_id = DOUBLE_EMMC_TOTAL_NS;
break;
case DUAL_CARD_AS_DUAL_NS: // 0xAA
ns_emmc_map.case_id = DOUBLE_EMMC_DOUBLE_NS;
break;
case DUAL_CARD_HIDE_EMMC0: // 0x11
ns_emmc_map.case_id = DOUBLE_EMMC_HIDE_NS0;
break;
case DUAL_CARD_HIDE_EMMC1: // 0x22
ns_emmc_map.case_id = DOUBLE_EMMC_HIDE_NS1;
break;
case ALL_CARD_HIDE_ALL_NS: // 0x00
ns_emmc_map.case_id = DOUBLE_EMMC_NO_NS;
break;
case BBS_0X80_DEFAULT:
// BIOS 未设置,等待配置
ns_emmc_map.case_id = WAIT_CFG_NS;
while (poll_ns_change() != 0); // 轮询等待 BIOS 设置
break;
}
}
break;
// ... 单卡情况处理
}
}

// Modern Standby 恢复时从 eMMC 恢复 Namespace 配置
void restore_dynamic_ns_from_modern_standby()
{
u32 buffer[128];
u32 bbs_reg_val;

// 只处理动态 Namespace 模式
if (ns_emmc_map.namespace_class != DYNAMIC_HIDE_NS)
return;

// 检查当前寄存器值,如果非默认则跳过(表示已由 BIOS 设置)
bbs_reg_val = (get_reg(BAYBRIDGE_NVME_CONTROLLER_BASE, 0x4C) >> 24) & 0xFF;
if (bbs_reg_val != BBS_0X80_DEFAULT)
return;

// 从 eMMC 保留块读取备份的配置
emmc_usersblock_readwrite(buffer, EMMC_RESERVE_BLOCK3_OFFSET,
EMMC_BLOCK_SIZE, READ_EMMC);
bbs_reg_val = buffer[0];

// 恢复有效的 Namespace 配置到寄存器
if (bbs_reg_val == DUAL_CARD_HIDE_EMMC0 ||
bbs_reg_val == DUAL_CARD_HIDE_EMMC1 ||
bbs_reg_val == DUAL_CARD_AS_DUAL_NS ||
bbs_reg_val == ALL_CARD_AS_SINGLE_NS) {
set_reg(BAYBRIDGE_NVME_CONTROLLER_BASE, 0x4C, 0xFF000000, bbs_reg_val << 24);
}
}

5. 固件更新机制

5.1 固件更新架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
┌──────────────────────────────────────────────────────────────────────────┐
│ 固件更新流程架构 │
├──────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ NVMe Admin Commands │ │
│ │ ┌──────────────────────┐ ┌──────────────────────────────┐ │ │
│ │ │ Firmware Image │ │ Firmware Commit │ │ │
│ │ │ Download (07h) │ │ (10h) │ │ │
│ │ │ • 分块传输 FW 数据 │ │ • 验证 FW 完整性 │ │ │
│ │ │ • 写入目标 Slot │ │ • 激活新固件 Slot │ │ │
│ │ └──────────────────────┘ └──────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ 存储目标 (Firmware Slots) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Slot 1 │ │ Slot 2 │ │ Slot 3 │ │ │
│ │ │ eMMC Boot │ │ eMMC Boot │ │ SPI Flash │ │ │
│ │ │ Partition 1 │ │ Partition 2 │ │ │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Slot 4 │ │ Slot 5 │ ← FFU (Field Firmware │ │
│ │ │ eMMC0 FFU │ │ eMMC1 FFU │ Update for eMMC chip) │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ FW Header 结构 (512 Bytes) │ │
│ │ │ │
│ │ Offset Field Description │ │
│ │ ────────────────────────────────────────────────────────── │ │
│ │ DWORD0 FW Size + Parity 固件大小 + 奇偶校验 │ │
│ │ DWORD1~7 Reserved 保留 │ │
│ │ DWORD32 Target Slot [7:4] 目标 Slot 编号 │ │
│ │ DWORD33+ SPI Config SPI Flash 配置参数 │ │
│ │ ... FW Binary 固件二进制数据 │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────┘

5.2 固件下载流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
┌──────────────────────────────────────────────────────────────────┐
│ Firmware Download 状态机 │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ │
│ │ IDLE │◀────────────────────────────────────────────┐ │
│ └──────┬──────┘ │ │
│ │ 收到 FW Download (offset=0) │ │
│ ▼ │ │
│ ┌─────────────────────────────┐ │ │
│ │ PARSE_HEADER │ │ │
│ │ • 解析 FW Size (DWORD0) │ │ │
│ │ • 奇偶校验 Header │ │ │
│ │ • 提取目标 Slot ID │ │ │
│ └──────────────┬──────────────┘ │ │
│ │ Header 有效 │ │
│ ▼ │ │
│ ┌─────────────────────────────┐ │ │
│ │ PREPARE_TARGET │ │ │
│ │ • Slot 1/2: 切换 eMMC 分区 │ │ │
│ │ • Slot 3: 擦除 SPI Flash │ │ │
│ │ • Slot 4/5: 初始化 FFU │ │ │
│ └──────────────┬──────────────┘ │ │
│ │ │ │
│ ▼ │ │
│ ┌─────────────────────────────┐ │ │
│ │ DOWNLOADING │◀─────────┐ │ │
│ │ • 接收 4KB 数据块 │ │ │ │
│ │ • 写入目标存储 │ │ 还有更多数据 │ │
│ │ • 更新 Offset │──────────┘ │ │
│ └──────────────┬──────────────┘ │ │
│ │ Offset == FW Size │ │
│ ▼ │ │
│ ┌─────────────────────────────┐ │ │
│ │ WAIT_COMMIT │ │ │
│ │ • 等待 FW Commit 命令 │ │ │
│ └──────────────┬──────────────┘ │ │
│ │ │ │
│ ▼ │ │
│ ┌─────────────────────────────┐ │ │
│ │ COMMITTED │─────────────────────────────┘ │
│ │ • 验证完整性 │ │
│ │ • 设置激活 Slot 寄存器 │ │
│ │ • 等待 Controller Reset │ │
│ └─────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘

5.3 核心实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// firmware_image_download.c - FW Header 校验
static boolean check_fw_header(u32 offset, u32 *completion_status)
{
// 读取 DWORD0: FW Size + Parity
global_fw_update_data.firmware_head_dword0 = global_fw_update_data.buffer[0];

// 空值检查(未烧录或擦除状态)
if (global_fw_update_data.firmware_head_dword0 == 0 ||
global_fw_update_data.firmware_head_dword0 == 0xFFFFFFFF) {
*completion_status = 0x107; // Invalid FW Image
return FALSE;
}

// 奇偶校验(4字节异或)
if (parity_check(1, (u32)&global_fw_update_data.firmware_head_dword0) != 0) {
*completion_status = 0x107;
return FALSE;
}

// 提取 FW Size(低24位)
global_fw_update_data.size = global_fw_update_data.firmware_head_dword0 & 0x00FFFFFF;

// 提取目标 Slot ID(DWORD32 的高4位)
global_fw_update_data.slot_id = (global_fw_update_data.buffer[32] >> 24) & 0x0F;

// 首次下载时清除 DWORD0,等待 Commit 时写回
if (offset == 0) {
global_fw_update_data.buffer[0] = 0x0;
global_fw_update_data.firmware_data_need_validation = 1;
}

return TRUE;
}

// firmware_commit.c - FW Commit 处理
void firmware_commit_process_update(command_p command)
{
u16 completion_status = 0;
u32 fw_slot = command->firmware_commit_dw10.firmware_slot;

// Slot 0 表示让控制器自动选择
if (fw_slot == 0 && global_fw_update_data.slot_id != 0) {
fw_slot = global_fw_update_data.slot_id;
}

// Slot 4/5: eMMC FFU
#if BB_FFU_SUPPORTED
if ((fw_slot == 4 || fw_slot == 5) && global_emmc_ffu_data.emmc_ffu_state_flg > 0) {
emmc_ffu_commit_process(command, completion_status);
return;
}
#endif

// 验证 FW 数据完整性
if (global_fw_update_data.firmware_data_need_validation) {
// 检查下载大小是否匹配
if (!global_fw_update_data.size ||
global_fw_update_data.size + FW_HEAD_SIZE != ((global_fw_update_data.offset + 1) << 2)) {
completion_status = 0x107; // Invalid FW Image
goto exit;
}

// 根据 Slot 写入 DWORD0 完成下载
if (fw_slot == 3) {
// SPI Flash
set_pinshare_mode(MODE_SPI);
u32 *dest = (u32 *)BAYBRIDGE_EEPROM_BASE;
*dest = global_fw_update_data.firmware_head_dword0;
} else if (fw_slot == 1 || fw_slot == 2) {
// eMMC Boot Partition
commit_firmware_update(fw_slot, global_fw_update_data.first_block,
0, sizeof(global_fw_update_data.first_block), 0);
}
}

// 设置激活 Slot 寄存器
if (completion_status == 0) {
u32 value = BAYBRIDGE_REG_FOR_ACTIVATED_SLOT & 0xFFFFFFFC;
BAYBRIDGE_REG_FOR_ACTIVATED_SLOT = value | fw_slot;
}

exit:
fn_memset(&global_fw_update_data, 0, sizeof(global_fw_update_data));
send_complete(command->command_identifier, 0, 0, completion_status);
}

6. Get Log Page 实现

6.1 支持的 Log Page 类型

Log Page ID 名称 描述
01h Error Information 错误信息日志
02h SMART / Health 健康状态信息
03h Firmware Slot 固件槽位信息
05h Commands Supported 支持的命令集
C0h Vendor Specific 厂商自定义(读取配置参数)

6.2 Log Page 处理流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// get_log_page.c - Log Page 分发处理
void get_log_page_process(command_p command)
{
u32 bytes_to_return = ((command->get_log_page_dw10.number_of_dwords_lower & 0xFFF) + 1) << 2;

// 检查 DMA 资源可用性
if (emmc_firmware_executing_task_completion != 1) {
// 暂存命令,等待 DMA 释放
store_admin_command(command, FUNC_TYPE_GET_LOGPAGE);
return;
}

fn_memset_4bytes((void *)BAYBRIDGE_DATA_BUFFER, 0, 0x1000);

switch (command->get_log_page_dw10.log_page_identifier) {
case 0x01: // Error Information
error_information_process(command, bytes_to_return);
break;

case 0x02: // SMART / Health Information
smart_health_information_process(command, bytes_to_return);
break;

case 0x03: // Firmware Slot Information
firmware_slot_information_process(command, bytes_to_return);
break;

case 0x05: // Commands Supported and Effects
commands_supported_and_effects(command, bytes_to_return);
break;

case 0xC0: // Vendor Specific: Read FW Parameters
read_out_header_parameter_process(command, bytes_to_return);
break;

default:
send_complete(command->command_identifier, 0, 0,
DO_NOT_RETRY | SCT_GENERIC_COMMAND_STATUS | SC_INVALID_FIELD_IN_COMMAND);
break;
}
}

// SMART Health Information 响应
static void smart_health_information_process(command_p command, u32 bytes_to_return)
{
smart_health_information_log_t info = {0};

// 填充 SMART 数据
info.critical_warning_and_temperature = smart_data.critical_warning_and_temperature;
info.percentage_used = smart_data.percentage_used;

// 填充可用空间百分比
info.critical_warning_and_temperature |= 0x64 << 24; // available_space = 100%
info.percentage_used |= 0x0A; // available_space_threshold = 10%

// 读写统计(需要字节序转换)
info.data_units_read_low = leon2_cpu_64bits_swap(smart_data.data_units_read_low);
info.data_units_written_low = leon2_cpu_64bits_swap(smart_data.data_units_written_low);
info.host_read_commands_low = leon2_cpu_64bits_swap(smart_data.host_read_commands_low);
info.host_write_commands_low = leon2_cpu_64bits_swap(smart_data.host_write_commands_low);
info.power_cycles_low = leon2_cpu_64bits_swap(smart_data.power_cycles_low);
info.power_on_hours_low = leon2_cpu_64bits_swap(smart_data.power_on_hours_low);

// DMA 传输响应数据
fn_memcpy_4bytes((void *)BAYBRIDGE_DATA_BUFFER, &info, bytes_to_return);
dma_data_transfer(command->prp.prp_entry1, command->prp.prp_entry2, bytes_to_return, 1, 1);
send_complete(command->command_identifier, 0, 0, 0);
}

7. 要点总结

7.1 SMART 信息实现要点

要点 说明
数据持久化 SMART 数据存储在 eMMC 保留块,掉电不丢失
定时更新 使用硬件 Timer 周期性更新运行时间和忙时间
IO 统计 每次读写操作实时更新统计计数器
大数值处理 128-bit 计数器支持 EB 级别数据量统计

7.2 磨损均衡相关

概念 Bridge 芯片的实现方式
FTL 层 不实现,由 eMMC 内部处理
磨损均衡 透传给 eMMC,读取 EXT_CSD 获取寿命信息
寿命估计 EXT_CSD[268/269] → SMART Percentage Used
预警机制 EXT_CSD[267] == 0x03 → Critical Warning

7.3 Model Name 动态控制

  • 位掩码设计:通过 model_number_field_enable 灵活控制显示字段
  • 运行时组装:从 eMMC CID/EXT_CSD 读取信息,动态拼接
  • OEM 定制:支持客户预设字符串覆盖自动检测值

7.4 固件更新安全性

机制 作用
奇偶校验 DWORD0 校验防止数据损坏
分步写入 先写数据,Commit 时才写 DWORD0
多 Slot 设计 支持回退到备份固件
FFU 支持 可在线更新 eMMC 芯片固件

8. 参考规范

  • NVMe Base Specification 1.4:Get Log Page, Firmware Update
  • eMMC 5.1 (JEDEC JESD84-B51):EXT_CSD Device Life Time 字段
  • SPARC LEON2:32-bit Timer 实现