Firmware Image Download 命令
在 NVMe 规范中,Firmware Image Download 命令用于从主机向 NVMe 控制器下载固件镜像。该命令是 NVMe 管理命令集的一部分,通常用于更新或安装新的固件。
1. 目的:
从主机传输固件镜像到 NVMe 控制器。
2. 流程:
通常在该命令之后跟随一个 Firmware Commit 命令,指示控制器验证并激活新下载的固件。
3.命令结构:
操作码:0x11(Firmware Image Download 命令)。
CDW10:包含要传输的 dword(4 字节单位)的数量。
CDW11:包含在固件镜像中的偏移量(以 dword 为单位),从这个偏移量开始传输。
4.数据传输:
固件镜像分块传输,每个块的大小在命令中指定。
可能需要多个 Firmware Image Download 命令才能传输整个镜像。
5.Firmware Commit 命令:
操作码:0x10(Firmware Commit 命令)。
在完整的固件镜像下载后发出此命令。
指示控制器验证并可选地激活新的固件镜像。
流程示例
1. 准备工作:
- 确保固件镜像在主机上可用,并准备传输。
- 确定块大小和传输整个镜像所需的块数量。
2. 下载块:
- 发出多个 Firmware Image Download 命令,每个命令传输固件镜像的一块。
- 每个命令指定块大小和固件镜像中的偏移量。
3. 提交固件:
在所有块下载完成后,发出 Firmware Commit 命令以验证并激活新的固件。
示例代码
以下是一个简化的伪代码示例,用于说明这一过程:
EFI_STATUS
FirmwareImageDownload(
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN VOID *Buffer,
IN UINTN BufferSize
)
{
EFI_STATUS Status;
NVME_COMMAND Command;
UINT64 Data;
UINTN Offset = 0;
UINTN ChunkSize = 4096; // 每次传输的块大小
UINT8 QueueEntrySize = sizeof(NVME_COMMAND);
// 准备命令
ZeroMem(&Command, sizeof(NVME_COMMAND));
Command.Opcode = FIRMWARE_IMAGE_DOWNLOAD_OPCODE;
Command.Prp1 = (UINT64)(UINTN)Buffer; // 指向要下载的固件数据缓冲区
while (Offset < BufferSize) {
UINTN BytesToTransfer = MIN(ChunkSize, BufferSize - Offset);
Command.Cdword10 = (UINT32)(BytesToTransfer / 4); // 传输的 dword 数量
Command.Cdword11 = (UINT32)(Offset / 4); // 偏移量
// 写入命令到 NVMe 控制器
Status = PciIo->Mem.Write(
PciIo,
EfiPciIoWidthUint32,
NVME_BAR,
NVME_ASQ,
QueueEntrySize,
&Command
);
if (EFI_ERROR(Status)) {
return Status;
}
// 轮询完成队列
// 在这里添加等待完成的代码
Offset += BytesToTransfer;
}
// 提交固件
ZeroMem(&Command, sizeof(NVME_COMMAND));
Command.Opcode = FIRMWARE_COMMIT_OPCODE;
Status = PciIo->Mem.Write(
PciIo,
EfiPciIoWidthUint32,
NVME_BAR,
NVME_ASQ,
QueueEntrySize,
&Command
);
return Status;
}
- 读写命令:
使用 PciIo->Mem.Write 方法向 NVMe 控制器的命令队列写入命令。 - 地址转换:
将固件缓冲区的虚拟地址转换为物理地址,写入命令结构中的 Prp1 字段。 - 轮询完成:
在写入命令后,轮询或等待完成队列以确保命令成功执行。 - 提交固件:
完成固件镜像下载后,发送固件提交命令以激活新的固件。
总结
通过 Firmware Image Download 命令,可以从主机向 NVMe 控制器下载固件镜像,通常在下载完成后,需要发出 Firmware Commit 命令以验证并激活新固件。该过程包括准备工作、分块下载固件镜像、提交固件等步骤。