概述
本文档以 BayHub BH799 NVMe-eMMC Bridge 芯片 的 Windows 固件升级工具为实例,系统讲解:
- MFC GUI 架构设计:对话框分层、控件通信机制、日志系统
- 固件升级流程:基于 Microsoft 官方文档的 IOCTL 接口实现
- 多平台适配:Microsoft Inbox Driver 与 Intel RST/VMD Driver 的差异与特殊处理
- 关键技术实现:固件头校验、防错机制、进度更新
1. MFC GUI 架构设计
1.1 整体架构
本工具采用 MFC 对话框分层架构,主对话框承载三个功能子页面(Tab Control),每个子页面独立处理特定功能:
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
| +------------------------------------------------------------------+ | BayHub Firmware Update Tool | +------------------------------------------------------------------+ | +------------------------------------------------------------+ | | | [Tab1: NVMe固件升级] [Tab2:eMMC升级] [Tab3:读取Flash头] | | | +------------------------------------------------------------+ | | | | | | | +------------------------------------------------------+ | | | | | 子对话框内容区域 | | | | | | | | | | | | - 设备选择 ComboBox | | | | | | - 固件文件路径 Edit + Browse按钮 | | | | | | - 固件槽位选择 ComboBox | | | | | | - 进度条 Progress Control | | | | | | - 升级按钮 / 检测按钮 | | | | | | | | | | | +------------------------------------------------------+ | | | | | | | +------------------------------------------------------------+ | | | | +------------------------------------------------------------+ | | | 日志输出区域 (ListBox) | | | | [2026-03-16 10:23:45] Device detected: BH799 NVMe | | | | [2026-03-16 10:23:46] Firmware version: 10100070 | | | | [2026-03-16 10:23:47] Downloading firmware... 10% | | | +------------------------------------------------------------+ | +------------------------------------------------------------------+
|
1.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
|
class CBBFirmwareupdatetoolDlg : public CDialogEx { public: CTabCtrl m_tabctrl; CListBox m_listboxctrl; CComboBox m_comboBox; eMMCFFUDlg emmcffudlg; FirmwareUpdateDlg fwupdatedlg; ReadFlashHeaderDlg readflashheaderdlg; NVME_DEVICE_LIST hNVMeDevices[MAX_DISK_NUMBER]; BB_DEVICE_LIST hBBDevices[MAX_DISK_NUMBER]; int m_radio1; CFile m_File; CString m_LogfileName; afx_msg LRESULT OnUpdatelistBox(WPARAM wParam, LPARAM lParam); };
|
关键设计点:
- 子对话框作为成员变量:避免频繁创建销毁,提高响应速度
- 公共资源集中在主对话框:设备列表、日志文件、平台选择由主对话框统一管理
- 消息机制实现线程安全:后台线程通过
PostMessage / SendMessage 更新 UI
1.3 图标与后台操作的通信机制
1.3.1 工作线程创建
固件升级是耗时操作(可能需要数分钟),必须在 后台线程 中执行,避免阻塞 UI 主线程:
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
|
void FirmwareUpdateDlg::OnBnClickedButton2() { m_hThread = CreateThread( NULL, 0, FirmwareUpgradeThread, this, 0, NULL ); GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE); }
DWORD WINAPI FirmwareUpdateDlg::FirmwareUpgradeThread(LPVOID lpParameter) { FirmwareUpdateDlg* pDlg = (FirmwareUpdateDlg*)lpParameter; CBBFirmwareupdatetoolDlg* pMain = pDlg->m_pMainDlg; int ret = DeviceFirmwareUpgrade( pMain->hNVMeDevices[pMain->m_iBBDevice].hDevice, pDlg->m_slotNum, (TCHAR*)(LPCTSTR)pDlg->m_str_bin_file, pDlg ); ::PostMessage(pMain->m_UIMainThreadId, WM_UPDATE_LISTBOX, 0, 0); return ret; }
|
1.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
| class CBBFirmwareupdatetoolDlg : public CDialogEx { afx_msg LRESULT OnUpdatelistBox(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() };
BEGIN_MESSAGE_MAP(CBBFirmwareupdatetoolDlg, CDialogEx) ON_MESSAGE(WM_UPDATE_LISTBOX, &CBBFirmwareupdatetoolDlg::OnUpdatelistBox) END_MESSAGE_MAP()
LRESULT CBBFirmwareupdatetoolDlg::OnUpdatelistBox(WPARAM wParam, LPARAM lParam) { fwupdatedlg.GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE); int count = m_listboxctrl.GetCount(); if (count > 0) { m_listboxctrl.SetCurSel(count - 1); } return 0; }
|
1.3.3 日志输出机制
日志同时输出到 UI ListBox 和 磁盘文件:
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
|
void CBBFirmwareupdatetoolDlg::WriteLogFile(CString str) { m_listboxctrl.AddString(str); int count = m_listboxctrl.GetCount(); if (count > 0) { m_listboxctrl.SetCurSel(count - 1); } if (m_logCreated) { SYSTEMTIME st; GetLocalTime(&st); CString timeStr; timeStr.Format(_T("[%04d-%02d-%02d %02d:%02d:%02d] "), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); m_File.Write(timeStr, timeStr.GetLength()); m_File.Write(str, str.GetLength()); m_File.Write(_T("\r\n"), 2); m_File.Flush(); } }
BOOL CBBFirmwareupdatetoolDlg::CreateLogFile() { CTime time = CTime::GetCurrentTime(); m_LogfileName = time.Format(_T("FWUpdate_%Y%m%d_%H%M%S.log")); BOOL ret = m_File.Open(m_LogfileName, CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive); if (ret) { m_logCreated = TRUE; } return ret; }
|
1.4 UI 控件与后台数据绑定
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 FirmwareUpdateDlg::SetProgressctrl(int offset) { ::PostMessage(this->m_hWnd, WM_UPDATE_PROGRESS, offset, 0); }
LRESULT FirmwareUpdateDlg::OnUpdateProgressCtrl(WPARAM wParam, LPARAM lParam) { int offset = (int)wParam; m_progressctrl.SetPos(offset); m_str_updating.Format(_T("升级中... %d%%"), offset); SetDlgItemText(IDC_STATIC_UPDATING, m_str_updating); return 0; }
BEGIN_MESSAGE_MAP(FirmwareUpdateDlg, CDialogEx) ON_MESSAGE(WM_UPDATE_PROGRESS, &FirmwareUpdateDlg::OnUpdateProgressCtrl) END_MESSAGE_MAP()
|
2. 固件升级流程实现
2.1 整体流程架构
参考 Microsoft 官方文档 Upgrading Firmware for an NVMe Device,固件升级分为三步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| +---------------------------------------------------------------------+ | NVMe 固件升级三步流程 | +---------------------------------------------------------------------+ | | | (1) 获取固件槽信息 (2) 下载固件镜像 (3) 激活固件 | | +--------------------+ +--------------------+ +--------------------+ | | | Get Firmware Info | | Firmware Download | | Firmware Commit | | | | | | | | | | | | - Slot Count | | - 分块传输 (4KB) | | - 指定目标槽位 | | | | - Active Slot | | - Offset 递增 | | - 重启生效 | | | | - Pending Slot | | - 每块等待完成 | | | | | | - ReadOnly 属性 | | | | | | | +--------------------+ +--------------------+ +--------------------+ | | | | IOCTL: IOCTL: IOCTL: | | FIRMWARE_FUNCTION_ FIRMWARE_FUNCTION_ FIRMWARE_FUNCTION_ | | GET_INFO DOWNLOAD ACTIVATE | | | +---------------------------------------------------------------------+
|
2.2 Microsoft Inbox Driver 方案
2.2.1 设备发现
1 2 3 4 5 6 7 8 9 10 11
|
int CBBFirmwareupdatetoolDlg::searchBBDevicesOnMicrosoftNVMePlatform(void) { CString inputCmd("wmic path win32_pnpentity where \"deviceid like '%PCI%'\" get deviceid"); wmicProcess(inputCmd); }
|
2.2.2 使用官方 Storage Firmware IOCTL
Microsoft 从 Windows 10 开始提供标准的存储固件升级接口:
| IOCTL |
功能 |
IOCTL_STORAGE_FIRMWARE_GET_INFO |
获取固件槽信息 |
IOCTL_STORAGE_FIRMWARE_DOWNLOAD |
下载固件镜像 |
IOCTL_STORAGE_FIRMWARE_ACTIVATE |
激活固件槽 |
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
|
int DeviceFirmwareUpgradeOnMicrosoftNVMePlatform( HANDLE _hDevice, BYTE bSlot, TCHAR* FileName, FirmwareUpdateDlg* pDlg) { STORAGE_FIRMWARE_INFO firmwareInfo; DeviceIoControl(hDevice, IOCTL_STORAGE_FIRMWARE_GET_INFO, ..., &firmwareInfo, ...); STORAGE_FIRMWARE_DOWNLOAD firmwareDownload; firmwareDownload.Version = 1; firmwareDownload.Size = sizeof(firmwareDownload); firmwareDownload.Offset = imageOffset; firmwareDownload.BufferSize = readLength; memcpy(firmwareDownload.ImageBuffer, buffer, readLength); DeviceIoControl(hDevice, IOCTL_STORAGE_FIRMWARE_DOWNLOAD, ..., &firmwareDownload, ...); STORAGE_FIRMWARE_ACTIVATE firmwareActivate; firmwareActivate.SlotToActivate = slotNumber; DeviceIoControl(hDevice, IOCTL_STORAGE_FIRMWARE_ACTIVATE, ..., &firmwareActivate, ...); }
|
2.3 Intel RST/VMD 方案
2.3.1 为什么需要特殊处理?
Intel RST (Rapid Storage Technology) 和 VMD (Volume Management Device) 使用 scsi miniport 架构,设备访问方式与 Microsoft inbox driver 不同:
| 特性 |
Microsoft Inbox Driver |
Intel RST/VMD |
| 设备句柄 |
\\.\PhysicalDriveN |
\\.\ScsiN |
| IOCTL 接口 |
IOCTL_STORAGE_FIRMARE_* |
IOCTL_SCSI_MINIPORT + IOCTL_NVME_PASS_THROUGH |
| NVMe 命令 |
内置封装 |
需要自行构造 NVMe Admin 命令 |
| SCSI 地址 |
不需要 |
需要 Bus/Target/LUN |
2.3.2 Intel RST 平台设备发现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
int CBBFirmwareupdatetoolDlg::searchBBDevicesOnIntelRSTPlatform(void) { CString inputCmd( "wmic diskdrive get firmwarerevision,model,scsibus,scsitargetid,scsilogicalunit" ); wmicProcess(inputCmd); hNVMeDevices[deviceIndex].SCSIBus = strtol(SCSIBus, NULL, 16); hNVMeDevices[deviceIndex].SCSITargetId = strtol(SCSITargetId, NULL, 16); hNVMeDevices[deviceIndex].SCSILogicalUnit = strtol(SCSILogicalUnit, NULL, 16); }
|
2.3.3 Intel RST NVMe 命令传递
Intel RST 环境下,需要通过 IOCTL_SCSI_MINIPORT 传递原始 NVMe 命令:
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
|
BOOL DeviceGetFirmwareInfoOnIntelRSTPlatform( HANDLE hDevice, PUCHAR Buffer, DWORD BufferLength, BOOLEAN DisplayResult, CBBFirmwareupdatetoolDlg* pMainDlg) { PSRB_IO_CONTROL srbControl; PNVME_IOCTL_PASS_THROUGH firmwareRequest; srbControl = (PSRB_IO_CONTROL)Buffer; srbControl->HeaderLength = sizeof(SRB_IO_CONTROL); srbControl->ControlCode = IOCTL_NVME_PASS_THROUGH; RtlMoveMemory(srbControl->Signature, INTELNVM_SIGNATURE, 8); srbControl->Timeout = 10; firmwareRequest = (PNVME_IOCTL_PASS_THROUGH)(Buffer); firmwareRequest->Version = NVME_PASS_THROUGH_VERSION; firmwareRequest->PathID = pMainDlg->hNVMeDevices[...].SCSIBus; firmwareRequest->TargetID = pMainDlg->hNVMeDevices[...].SCSITargetId; firmwareRequest->Lun = pMainDlg->hNVMeDevices[...].SCSILogicalUnit; firmwareRequest->Parameters.Command.CDW0.OPC = NVME_ADMIN_COMMAND_GET_LOG_PAGE; firmwareRequest->Parameters.Command.u.GETLOGPAGE.CDW10_V13.LID = NVME_LOG_PAGE_FIRMWARE_SLOT_INFO; firmwareRequest->Parameters.Command.u.GETLOGPAGE.CDW10_V13.NUMDL = 64/sizeof(DWORD) - 1; return DeviceIoControl(hDevice, IOCTL_SCSI_MINIPORT, Buffer, BufferLength, Buffer, BufferLength, &returnedLength, NULL); }
|
2.3.4 Intel RST 固件下载实现
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
|
while (moreToDownload) { firmwareRequest->Parameters.Command.CDW0.OPC = 0x19; firmwareRequest->Parameters.Command.CDW10 = (ChunkSize / 4) - 1; firmwareRequest->Parameters.Command.CDW11 = imageOffset / 4096; memcpy(buffer + firmwareRequest->Parameters.DataBufferOffset, fileBuffer + imageOffset, ChunkSize); result = DeviceIoControl(hDevice, IOCTL_SCSI_MINIPORT, buffer, bufferSize, buffer, bufferSize, &returnedLength, NULL); imageOffset += ChunkSize; int progress = (imageOffset * 100) / FileSize; pDlg->SetProgressctrl(progress); }
firmwareRequest->Parameters.Command.CDW0.OPC = 0x10;
firmwareRequest->Parameters.Command.CDW10 = (slotNumber << 24) | 0x01;
DeviceIoControl(hDevice, IOCTL_SCSI_MINIPORT, ...);
|
3. 多平台适配架构设计
3.1 平台选择机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
int DeviceFirmwareUpgrade( HANDLE _hDevice, BYTE bSlot, TCHAR* FileName, FirmwareUpdateDlg* pDlg) { if (pDlg->m_pMainDlg->m_radio1 == 0) { return DeviceFirmwareUpgradeOnMicrosoftNVMePlatform(...); } else { return DeviceFirmwareUpgradeOnIntelRSTPlatform(...); } }
|
3.2 设备列表管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
typedef struct NVME_DEVICE_LIST { HANDLE hDevice; char wide_FR[256]; char wide_MN[256]; ULONG SCSIBus; ULONG SCSITargetId; ULONG SCSILogicalUnit; } NVME_DEVICE_LIST, *PNVME_DEVICE_LIST;
int NVMeDevicesIndexMap[MAX_DISK_NUMBER];
|
3.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
| +------------------------------------------------------------------+ | Firmware Update GUI (MFC) | +------------------------------------------------------------------+ | | | +------------------+ +------------------+ +-----------------+ | | | 设备检测 Tab | | NVMe升级 Tab | | eMMC升级 Tab | | | +--------+---------+ +--------+---------+ +--------+--------+ | | | | | | | v v v | | +------------------------------------------------------------+ | | | CBBFirmwareupdatetoolDlg (主对话框) | | | | - 平台选择 (m_radio1) | | | | - 设备列表管理 | | | | - 日志输出 | | | +---------------------------+--------------------------------+ | | | | +------------------------------+----------------------------------+ | v +------------------------------------------------------------------+ | FirmwareUpgrade.cpp | +------------------------------------------------------------------+ | | | +----------------------------+ +---------------------------+ | | | DeviceFirmwareUpgrade() | | 平台分发函数 | | | | (统一入口) | | | | | +----------------------------+ +---------------------------+ | | | | | | v v | | +----------------------------+ +---------------------------+ | | | Microsoft Inbox Driver | | Intel RST/VMD | | | | | | | | | | - IOCTL_STORAGE_FIRMWARE_*| | - IOCTL_SCSI_MINIPORT | | | | - 标准 Windows 存储栈 | | - NVMe Pass-Through | | | | - \\.\PhysicalDriveN | | - \\.\ScsiN | | | +----------------------------+ +---------------------------+ | | | +------------------------------------------------------------------+
|
4. 关键技术实现
4.1 固件头防错机制(Fool Proof)
为防止用户误刷不兼容的固件,工具实现了 固件头校验 功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
if (pDlg->m_header_fool_proof_enable == TRUE) { result = DeviceVendorSpecificCMDOnIntelRSTPlatform( _hDevice, buffer, bufferSize, TRUE, pMainDlg); PNVME_FLASH_HEADER_PARAMETER_INFO pheader = (PNVME_FLASH_HEADER_PARAMETER_INFO)firmwareInfo; }
|
固件头结构定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
typedef struct _NVME_FLASH_HEADER_PARAMETER_INFO { DWORD dwSpiPageProgram; DWORD dwSpiCtrlIoTiming; DWORD dwSpiEraseCfgReg1; DWORD dwFwSlot; DWORD dwNamespaceClass; DWORD dwEmmcHideClass; DWORD dwNvmeNumberOfQueues; char cFwSignature[8]; char cFwRevision[8]; char cFwMd5Hash[16]; } NVME_FLASH_HEADER_PARAMETER_INFO;
|
4.2 MD5 完整性校验
固件镜像在下载前需要进行完整性校验:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
int Cfw_update_process::Md5Check() { HANDLE hFile = CreateFile(m_inputFWbinFile, GENERIC_READ, ...); SetFilePointer(hFile, FW_CUSTOMER_MD5_START_OFFSET, NULL, FILE_BEGIN); DWORD bytesRead; BYTE fileMd5[MD5LEN]; ReadFile(hFile, fileMd5, MD5LEN, &bytesRead, NULL); BYTE computedMd5[MD5LEN]; CalculateMd5(buffer, buffer_length, computedMd5); if (memcmp(fileMd5, computedMd5, MD5LEN) != 0) { return -1; } return 0; }
|
4.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
|
int Cfw_update_process::ParseParameterData(std::string& param_data) { for (auto& param : m_vParameters) { if (param.m_customer_readable) { WriteParameterToBin(param); } } }
int Cfw_update_process::MergeSkippedParametersToBinFile(void) { ReadFirmwareBinFile(m_inputFWbinFile); ReadParameterData(m_str_skipped_cfg_file); ParseParameterData(param_data); Md5Check(); SaveTheBinFile(m_outputFWbinFile, m_buffer_length); }
|
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
| +------------------------------------------------------------------+ | BayHub Firmware Update Tool v1.0.16 _ [] X | +------------------------------------------------------------------+ | | | +------------------------------------------------------------+ | | | O Microsoft NVMe Driver O Intel RST/VMD Driver | | | +------------------------------------------------------------+ | | | | +------------------------------------------------------------+ | | | [Tab1: NVMe固件升级] [Tab2:eMMC升级] [Tab3:读取Flash头] | | | +------------------------------------------------------------+ | | | | | | | 设备检测(D): [检测设备_______________▼] [关键词:___] | | | | [x] 保存设置 | | | | | | | | 当前设备: NVMe BAYHUB BH799 固件版本: 10100070 | | | | | | | | 固件文件: [________________________] [浏览...] | | | | | | | | 固件槽位: [Slot 1 (当前活跃)___▼] | | | | [x] 启用固件头防错检查 | | | | | | | | 参数配置: [________________________] [浏览...] | | | | | | | | [=========== ] | | | | 升级 | | | +------------------------------------------------------------+ | | | | +------------------------------------------------------------+ | | | [INFO] 2026-03-16 10:23:45 Device detected... | | | | [INFO] 2026-03-16 10:23:46 FW version: 10100070 | | | | [INFO] 2026-03-16 10:23:47 Downloading: 10% | | | +------------------------------------------------------------+ | +------------------------------------------------------------------+
|
5.2 典型使用流程
- 选择平台:根据目标机器的驱动类型选择 Microsoft NVMe 或 Intel RST
- 检测设备:点击”检测设备”按钮,列出系统中所有 BayHub 设备
- 选择固件:浏览并选择要升级的 .bin 文件
- 选择槽位:选择目标固件槽位(自动获取当前活跃槽位)
- (可选)启用防错:勾选固件头校验,防止参数不兼容
- 开始升级:点击”升级”按钮,等待完成
- 重启生效:升级完成后提示用户重启系统
6. 总结
本文档系统讲解了 Windows 平台 NVMe 固件升级工具的完整实现:
- MFC GUI 架构:对话框分层设计、工作线程与 UI 线程通信、日志系统
- 固件升级流程:三步走(获取信息→下载→激活),参考 Microsoft 官方文档
- 多平台适配:Microsoft Inbox Driver 与 Intel RST/VMD 的差异,平台抽象层设计
- 关键技术:固件头防错、MD5 校验、参数配置
该工具已支持 BH799 芯片,可作为其他存储设备固件升级工具的参考实现。