石家庄网站建设公司黄页,discuz和wordpress哪个好,iis网站后台登不进,网络设计网站多少钱1. 前言
随着数字化时代的发展#xff0c;数字数据的量越来越大#xff0c;相应的数据存储的需求也越来越大#xff0c;存储设备产业也是蓬勃发展。存储设备产业中#xff0c;发展最为迅猛的则是固态存储(Solid State Storage#xff0c;SSS)。数字化时代#xff0c;海量…1. 前言
随着数字化时代的发展数字数据的量越来越大相应的数据存储的需求也越来越大存储设备产业也是蓬勃发展。存储设备产业中发展最为迅猛的则是固态存储(Solid State StorageSSS)。数字化时代海量的数据需要海量的存储设备。可以说固态存储设备是数字化时代最重要的基础设施。 为了解决发现的Bug安全漏洞或者为了提升性能固态存储设备也有升级其固件的需求。固态存储设备种类繁多有可以随身携带的U盘、TF卡也有手机中的eMMCUFS还有电脑中的固态硬盘(SSD)更有各种云背后的分布式存储系统中大量使用的各种固态存储设备。不同应用场景其使用方式也不同那么相应的升级方式也有可能不同。本文尝试全面介绍一下不同应用场景下的固态存储设备的固件升级方案。
2. 固态存储设备
固态存储设备的主要构成为存储介质控制芯片和一些外置电子元器件。固态存储设备的主要存储介质为非易失性存储器其主要为NAND Flash。控制芯片的主要作用是连接NAND Flash和主机存储接口并管理存储在NAND Flash上的数据。 主机存储接口不同应用的场景也不同。其主要分为 ● USB接口主要用于移动存储 ● SD接口主要用于小型电子设备如相机监控设备等 ● eMMC接口主要用于手机、平板和一些嵌入式设备如智能电视车机等 ● UFS接口主要用于手机 ● SATA接口主要用于个人电脑 ● PCIe接口主要用于对性能有更高要求的企业级存储如分布式存储云存储等。
3. 升级方案
存储设备是否支持固件升级需要两个方面的支持存储设备固件算法支持升级并且有升级工具。
3.1. 固件算法
存储设备升级成功或者万一在升级过程中断电都不能影响存储设备上之前存放的用户数据。升级算法设计要点 ● 用户数据的正确性即L2P表(存储设备逻辑到NAND Flash物理地址映射表)不能发生改变。 ○ FTL算法设计的时候需要将L2P表等影响用户数据的算法数据结构和其他算法数据结构分块存储。因为升级固件必须重新写入算法二进制文件和重新配置Boot信息因为NAND Flash的块必须擦除了才能写所以固件二进制文件和Boot信息必须和L2P表分块存储。 ● 异常行为的安全性即升级过程中发生异常重新上电时能够恢复原有的状态。 ○ 升级的操作过程是日志型的每一步操作都有记录只有最后升级成功并且有CheckSum校验机制来保证操作的完整性。 ○ 升级算法的设计新旧算法都保留每次升级成功之后将新算法头中索引加1这样每次启动后检测到两个算法并通过CheckSum校验算法的完整性最后比较算法头中的索引值启动索引较大的算法。
3.2. 升级流程
3.2.1. 移动存储设备
移动存储设备U盘/TF卡基本都可以通过USB接口接入电脑电脑的操作系统主要包括Windows和Linux。所以针对移动存储设备主要考虑制作系统软件来应对此类升级。为了减少软件开发工作建议使用跨平台方案保证最大限度的复用代码。为了更好地操作底层API并且有效率的开发软件采用C作为软件开发语言选用Qt作为跨平台的开发框架并且都采用g编译器。无论是在Linux平台还是在Windows平台升级的基本流程基本是相同的。如下图
抽象出Linux和Windows下不同点统一抽象的接口然后复用宏WIN32区分不同系统主要包括
设备的标识Windows下以盘符(E:\F:\等)作为标识Linux下则以设备路径(/dev/sdb, /dev/sdc等)作为标识。文件路径Windows下以反斜杠\作为分隔符Linux下则以斜杠/作为分隔符。和设备通信和USB设备通信数据层是采用SCSI协议传输层采用的USB协议。应用软件直接采用SCSI协议与设备进行通信即可。 a. Windows层的通信主要代码
// Open device
char szLetter[] \\.\G:;
HANDLE hDev CreateFile((LPCSTR)_devFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);// Transport CMD to device
if (!DeviceIoControl(hDev,IOCTL_SCSI_PASS_THROUGH,pt,sizeof(buf),buf,sizeof(buf),bytes,NULL)) {printf(IOCTL failed %d\n, GetLastError());}// Close device
CloseHandle(hDev);b. Linux下通信的主要代码
// Open device
int fd open(/dev/sde, O_RDWR);// Transport CMD
unsigned char buff[1024] {0};
unsigned char inq_cmd[] {WRITE_10, 00, 0, 0, 0, 0, 0, 0, 0x2, 0};
unsigned char sense[32] {0};
struct sg_io_hdr io_hdr {};
io_hdr.interface_id S;
io_hdr.cmdp inq_cmd;
io_hdr.cmd_len sizeof(inq_cmd);
io_hdr.dxferp buff;
io_hdr.dxfer_len 32;
io_hdr.dxfer_direction SG_DXFER_TO_DEV;
io_hdr.sbp sense;
io_hdr.mx_sb_len sizeof(sense);
io_hdr.timeout 5000;
ioctl(fd, SG_IO, io_hdr);// Close device
close(fd);3.2.2. eMMC/UFS
eMMC/UFS主要用于手机、平板和一些嵌入式设备手机和平板基本是Andriod系统嵌入式也多是Andriod和Linux。而Andriod的内核也基本上就是Linux内核了。Andriod因为安全机制不允许应用程序直接与存储储备通信所有的数据传输都是加密的所以Andriod也不方便通过应用程序来进行升级固件。 无论是Andriod还是嵌入式Linux都是通过u-boot来启动系统的。u-boot中都已经携带有eMMC/UFS的驱动代码并且u-boot中都会初始化eMMC/UFS然后读取存放在eMMC/UFS上的系统进行引导启动。所以在u-boot中进行固件升级不仅可以绕开Andriod的安全机制升级方式也可以与Linux统一。 eMMC自从协议4.0版之后协议提出统一的固件更新规则FFU(Field Firmware Update现场固件更新)。其基本流程为Host发送命令进入FFU模式通过写命令将固件bin文件写入设备存储在NAND Flash相应位置然后Host发送激活命令、或硬件复位或者断上电操作就可以完成固件更新。 其协议流程为
u-boot流程修改完u-boot之后编译成二进制文件然后与Andriod文件一起推送到手机终端等待用户升级系统过程中先完成对eMMC/UFS的升级。
// 在mmc_inti之后执行如下流程
mmc_set_clock(mmc, mmc-tran_speed,MMC_CLK_ENABLE);
mmc_switch(mmc, FFU_MODE);
mmc_write(mmc, addr, buff, size);
mmc_switch(mmc, NORMAL_MODE);
mmc_power_cycle(mmc);UFS协议继承了eMMC的FFU其流程基本一样只不过在激活新固件时简化了eMMC原有的方式只支持HW Reset或Power Cycle。
3.2.3. SATA SSD
SATA接口的SSD主要用于个人电脑。如果SSD作为电脑的从盘(非操作系统盘)则可以直接使用系统软件。如果SSD作为电脑的主盘(操作系统盘)由于操作系统的限制无法直接与主盘通信。操作系统有MAC、Windows、Linux等而且cpu内核也有x86/x86-64/Arm等如果要编译系统软件会有很多版本。有没有一种通用的方法兼容所有情况呢 为了解决主盘无法直接升级需要另外接入系统让主盘作为从盘。
3.2.3.1. UEFI应用
当前电脑系统的启动都是通过UEFI来引导启动操作系统的可以考虑编写UEFI应用程序通过UEFI程序来完成对SSD固件的更新。
3.2.3.2. WinPE应用
现在安装系统都是使用U盘来完成系统先在U盘中安装一个Win PE的启动系统来引导安装操作系统。Win PE是一个简化版的Windows系统可以运行基本的Windows应用程序。这种方式可以不用管电脑原来是什么操作系统只需要针对不同CPU制作不同的Win PE启动盘即可。 ● 升级工具 SATA接口的SSD使用ATA协议来通信并且兼容SCSI的通用命令。 可以通过SCSI的3种操作码来配置3种ATA通信协议。
主要通信代码
SCSI_PASS_THROUGH spt {0};
spt.Length sizeof(SCSI_PASS_THROUGH);
spt.TimeOutValue 2;
spt.CdbLength 12; // 16,32
spt.Cdb[0] 0xA1; // 0x85,0x7F
spt.Cdb[1] 3 1;
memcpy(spt.Cdb[3], aptex.CurrentTaskFile, 8);
ret DeviceIoControl(handle, IOCTL_SCSI_PASS_THROUGH,spt, sizeof(SCSI_PASS_THROUGH), NULL, 0, nRet, NULL);
也可以直接通过ATA协议来与设备通信其主要代码
ATA_PASS_THROUGH_EX aptex {0};
aptex.Length sizeof(ATA_PASS_THROUGH_EX);
aptex.TimeOutValue 2;
aptex.CurrentTaskFile[6] 0xEF;
aptex.CurrentTaskFile[0] 0x05;
aptex.CurrentTaskFile[1] 0x80;
ret DeviceIoControl(handle, IOCTL_ATA_PASS_THROUGH, aptex, sizeof(ATA_PASS_THROUGH_EX), NULL, 0, nRet, NULL);● WinPE系统盘
制作WinPE需要安装ADK不同版本WinPE对应不同的ADK下载合适的ADK版本安装。以管理员身份启动“部署和映像工具环境” 。运行“copype”以创建 Windows PE 文件的工作副本。 // 提取64位的WinPE资源文件 copype amd64 C:\WinPE_amd64 // 提取32位的WinPE资源文件 copype x86 C:\WinPE_x86提取镜像中文件在WinPE中添加固件更新工具。 把fw_update_tool.exe放在mout\Program Files目录。启动WinPE之后自动执行升级工具。 wpeinit cd … cd “Program Files\FWupdateTool” FWupdateTool.exe提交修改 将相关的修改提交到新的winpe.wim中并卸载所有提取的文件。 Dism /unmount-Wim /MountDir:C:\winpe_x86\mount /Commit拷贝Winpe.wim至IOS目录 copy winpe.wim C:\winpe_x86\ISO\sources\boot.wim /y生成镜像文件 oscdimg -n -bC:\winpe_x86\etfsboot.com C:\winpe_x86\iso C:\winpe.iso利用Ultraiso写入镜像 利用Ultraiso打开Winpe.iso然后菜单选择启动-写入硬盘映像选择指定U盘点击确认等待完成winpe启动盘即制作完成。 也可以使用命令行制作WinPE系统
set PEPathC:\win10PE_x86
call C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat
if exist %PEPath% rmdir /s /q %PEPath%
call CopyPE.cmd x86 %PEPath%
Dism /Mount-Image /ImageFile:%PEPath%\media\sources\boot.wim /index:1 /MountDir:%PEPath%\mount
pause
Dism /Unmount-Image /MountDir:%PEPath%\mount /commit
rem MakeWinPEMedia /ISO %PEPath% %PEPath%\Win10PE_x86.ISO
MakeWinPEMedia /ufd %PEPath% g:3.2.4. PCIe SSD
PCIe接口的SSD主要用高性能场景如高价个人电脑还有云存储、企业分布式存储等。PCIe接口的SSD采用NVMe通信协议协议中也有规定固件升级流程和FFU流程大同小异下载固件激活固件。 ● Windows下的实现流程
BOOL DeviceStorageFirmwareUpgrade(int _nPhyNo, BYTE _slotID)
{QString strDeviceName QString(%1%2).arg(\\\\.\\Physicaldrive).arg(_nPhyNo);HANDLE deviceHandle CreateFile(strDeviceName.toStdWString().data(),GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,nullptr,OPEN_EXISTING,FILE_FLAG_NO_BUFFERING,nullptr);if (deviceHandle INVALID_HANDLE_VALUE){return FALSE;}// Setup header of firmware download data structure.const DWORD dwBuffSize FIELD_OFFSET(STORAGE_HW_FIRMWARE_DOWNLOAD, ImageBuffer) 4*1024;QScopedPointerchar scopeBuff(new char[dwBuffSize]());PSTORAGE_HW_FIRMWARE_DOWNLOAD firmwareDownload reinterpret_castPSTORAGE_HW_FIRMWARE_DOWNLOAD(scopeBuff.get());firmwareDownload-Version sizeof(STORAGE_HW_FIRMWARE_DOWNLOAD);firmwareDownload-Size dwBuffSize;firmwareDownload-Flags STORAGE_HW_FIRMWARE_REQUEST_FLAG_CONTROLLER;firmwareDownload-Slot 0x11;// Open image file and download it to controller.ULONGLONG imageBufferLength dwBuffSize - FIELD_OFFSET(STORAGE_HW_FIRMWARE_DOWNLOAD, ImageBuffer);QString strFilePath :/libra_cpu01_sysfw.bin;QFile file(strFilePath);if (!file.open(QIODevice::ReadOnly)){qDebug()Open strFilePath failed.;return FALSE;}ULONG imageOffset 0;BOOL moreToDownload TRUE;while (moreToDownload){RtlZeroMemory(firmwareDownload-ImageBuffer, imageBufferLength);qint64 readLength file.read(reinterpret_castchar*(firmwareDownload-ImageBuffer), static_castqint64(imageBufferLength));if (readLength 0){file.close();break;}firmwareDownload-Offset imageOffset;firmwareDownload-BufferSize min(imageBufferLength, static_castULONG(readLength));ULONG returnedLength 0;BOOL result DeviceIoControl(deviceHandle,IOCTL_STORAGE_FIRMWARE_DOWNLOAD,scopeBuff.get(),dwBuffSize,scopeBuff.get(),dwBuffSize,returnedLength,nullptr);if (!result){return FALSE;}imageOffset static_castULONG(firmwareDownload-BufferSize);}// Activate the newly downloaded image.RtlZeroMemory(scopeBuff.get(), dwBuffSize);PSTORAGE_HW_FIRMWARE_ACTIVATE firmwareActivate reinterpret_castPSTORAGE_HW_FIRMWARE_ACTIVATE(scopeBuff.get());firmwareActivate-Version sizeof(STORAGE_HW_FIRMWARE_ACTIVATE);firmwareActivate-Size sizeof(STORAGE_HW_FIRMWARE_ACTIVATE);firmwareActivate-Slot _slotID;firmwareActivate-Flags STORAGE_HW_FIRMWARE_REQUEST_FLAG_CONTROLLER;// activate firmwareULONG returnedLength 0;BOOL result DeviceIoControl(deviceHandle,IOCTL_STORAGE_FIRMWARE_ACTIVATE,scopeBuff.get(),dwBuffSize,scopeBuff.get(),dwBuffSize,returnedLength,nullptr);return result;
}● Linux下有开源工具NVME-cli可以直接使用 nvme fw-download /dev/nvme0 -f allBinary.bin nvme fw-commit /dev/nvme0-s 2 -a 1# 参数-s代表slot。标准定义SSD支持7个slotslot 1 是只读权限用于存放出厂固件slot 2和3 可用于固件下载。# 参数-a代表不同的升级方法常用的有两个。001b向指定slot下载固件需要reset后完成激活操作# 011b向指定slot下载固件激活立即生效固件升级完成)4. 参考资料
NVM Express TM Revision 1.4Information technology -SCSI / ATA Translation - 5 (SAT-5)ATA Command Pass-ThroughUniversal Serial Bus Mass Storage Class UFI Command SpecificationUniversal Flash Storage (UFS)Version 3.1Embedded Multi-Media Card (e•MMC) Electrical Standard (5.1)https://github.com/linux-nvme/nvme-cli/https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ni-winioctl-ioctl_storage_firmware_activatehttps://learn.microsoft.com/zh-cn/windows-hardware/manufacture/desktop/winpe-intro?viewwindows-11https://github.com/u-boot/u-boot