概述
本文介绍 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
| typedef struct { u32 available_spare:8; u32 available_space_threshold:8; u32 critical_warning_and_temperature; u32 percentage_used;
u64 data_units_read_low; 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
| 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; if (fw_param.emmc_resv_blk_mod) smart_rw->addr_offset = EMMC_RESERVE_BLOCK4_OFFSET; else smart_rw->addr_offset = EMMC_RESERVE_BLOCK2_OFFSET; smart_info_emmc_rw(smart_rw, smart_data); }
void smart_info_update_by_timer(timer_flags_p timer_flags, smart_rw_emmc_p smart_rw, smart_health_info_data_p smart_data) { 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); } 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; } 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; } }
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; 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
|
#if BB_MMC_SWEAR_ENABLE #else #endif
|
2.2 SWEAR 核心概念
Particle 概念
1 2 3 4 5 6
| #define WL_M (1024 * WL_K) #define WL_K 1024 #define PARTCIAL_SIZE (u32)((1 << (fw_param.particle_size_cfg)) * (4 * WL_K))
|
逻辑空间划分
当两个 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
|
void emmc_capacity_parse(chip_data_info_t *chip_data_info) { 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; }
chip_data_info->partcial_count = min_cap / PARTCIAL_SIZE; chip_data_info->last_part_size = min_cap % PARTCIAL_SIZE;
chip_data_info->section1_size = chip_data_info->partcial_count * PARTCIAL_SIZE * 2;
chip_data_info->section2_size = chip_data_info->last_part_size * 2;
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
|
void calculate_start_address(u32 address, chip_data_info_t *chip_data_info) { u32 head_part_count = address / PARTCIAL_SIZE; u32 head_part_offset = address % PARTCIAL_SIZE;
if((head_part_count % 2) == 0) { chip_data_info->start_chip = 0; chip_data_info->emmc[0].addr = (head_part_count/2) * PARTCIAL_SIZE + head_part_offset; } else { chip_data_info->start_chip = 1; 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
|
typedef enum { SEC1_SEC1 = 0, SEC1_SEC2_EMMC0, SEC1_SEC2_EMMC1, SEC1_SEC3, SEC2_EMMC0_SEC2_EMMC0, SEC2_EMMC0_SEC2_EMMC1, SEC2_EMMC1_SEC2_EMMC1, SEC2_EMMC0_SEC3, SEC1_SEC2_SEC3, SEC2_EMMC1_SEC3, SEC3_SEC3, } data_cover_type;
|
2.6 保留区域处理
1 2 3 4 5 6 7 8
| 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)) { 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
|
particle_size_cfg:0xA
|
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
| void emmc_features_query(u8 card_slot) { init_capability_temperature(card_slot);
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; }
u8 emmc_life_used_value = card_info.ext_csd[268] | card_info.ext_csd[269];
card_info.perc_used[card_slot] = 10 * (emmc_life_used_value > 0 ? emmc_life_used_value - 1 : 1);
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
| 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); 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
| static void model_name_init() { if (*(u32 *)(&fw_param.model_number[0]) != 0) { fn_memcpy((byte *)BBS_MODEL_NUMBER_ADDR, (byte *)fw_param.model_number, 40); return; } byte mn_str[40] = {0}; mn_field_t mn_field = {0}; if (assert_mn_field_enable(MN_BIT_ENABLE_MASK_VEN_NAME)) { 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)) { 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)) { 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)) { 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)) { 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)) { mn_field.postfix_len = create_mn_postfix_str(mn_str + mn_field.total_len); mn_field.total_len += mn_field.postfix_len; } 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); }
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; 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
| static void namespace_mapping_init() { ns_emmc_map.namespace_class = fw_param.namespace_class; ns_emmc_map.emmc_num = get_card_num(); 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: ns_emmc_map.case_id = DOUBLE_EMMC_TOTAL_NS; break; case DUAL_CARD_AS_DUAL_NS: ns_emmc_map.case_id = DOUBLE_EMMC_DOUBLE_NS; break; case DUAL_CARD_HIDE_EMMC0: ns_emmc_map.case_id = DOUBLE_EMMC_HIDE_NS0; break; case DUAL_CARD_HIDE_EMMC1: ns_emmc_map.case_id = DOUBLE_EMMC_HIDE_NS1; break; case ALL_CARD_HIDE_ALL_NS: ns_emmc_map.case_id = DOUBLE_EMMC_NO_NS; break; case BBS_0X80_DEFAULT: ns_emmc_map.case_id = WAIT_CFG_NS; while (poll_ns_change() != 0); break; } } break; } }
void restore_dynamic_ns_from_modern_standby() { u32 buffer[128]; u32 bbs_reg_val; if (ns_emmc_map.namespace_class != DYNAMIC_HIDE_NS) return; bbs_reg_val = (get_reg(BAYBRIDGE_NVME_CONTROLLER_BASE, 0x4C) >> 24) & 0xFF; if (bbs_reg_val != BBS_0X80_DEFAULT) return; emmc_usersblock_readwrite(buffer, EMMC_RESERVE_BLOCK3_OFFSET, EMMC_BLOCK_SIZE, READ_EMMC); bbs_reg_val = buffer[0]; 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
| static boolean check_fw_header(u32 offset, u32 *completion_status) { 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; return FALSE; } if (parity_check(1, (u32)&global_fw_update_data.firmware_head_dword0) != 0) { *completion_status = 0x107; return FALSE; } global_fw_update_data.size = global_fw_update_data.firmware_head_dword0 & 0x00FFFFFF; global_fw_update_data.slot_id = (global_fw_update_data.buffer[32] >> 24) & 0x0F; if (offset == 0) { global_fw_update_data.buffer[0] = 0x0; global_fw_update_data.firmware_data_need_validation = 1; } return TRUE; }
void firmware_commit_process_update(command_p command) { u16 completion_status = 0; u32 fw_slot = command->firmware_commit_dw10.firmware_slot; if (fw_slot == 0 && global_fw_update_data.slot_id != 0) { fw_slot = global_fw_update_data.slot_id; } #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 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; goto exit; } if (fw_slot == 3) { 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) { commit_firmware_update(fw_slot, global_fw_update_data.first_block, 0, sizeof(global_fw_update_data.first_block), 0); } } 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
| void get_log_page_process(command_p command) { u32 bytes_to_return = ((command->get_log_page_dw10.number_of_dwords_lower & 0xFFF) + 1) << 2; if (emmc_firmware_executing_task_completion != 1) { 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_process(command, bytes_to_return); break; case 0x02: smart_health_information_process(command, bytes_to_return); break; case 0x03: firmware_slot_information_process(command, bytes_to_return); break; case 0x05: commands_supported_and_effects(command, bytes_to_return); break; case 0xC0: 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; } }
static void smart_health_information_process(command_p command, u32 bytes_to_return) { smart_health_information_log_t info = {0}; 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; info.percentage_used |= 0x0A; 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); 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 实现