使用 Windows 更新 更新设备固件

本文介绍如何使用 Windows 更新 (WU) 服务更新可移动或机箱内设备的固件。 有关更新系统固件的信息,请参阅 Windows UEFI 固件更新平台

为此,你将提供一种更新机制,该机制作为包含固件有效负载的设备驱动程序实现。 如果设备使用供应商提供的驱动程序,可以选择将固件更新逻辑和有效负载添加到现有函数驱动程序,或提供单独的固件更新驱动程序包。 如果设备使用 Microsoft 提供的驱动程序,则必须提供单独的固件更新驱动程序包。 在这两种情况下,固件更新驱动程序包都必须是通用的。

有关通用驱动程序的详细信息,请参阅 Windows 驱动程序入门。 驱动程序二进制文件可以使用 KMDFUMDF 2Windows 驱动程序模型

由于 WU 无法执行软件,因此固件更新驱动程序必须将固件交给即插即用 (PnP) 进行安装。

固件更新驱动程序操作

通常,固件更新驱动程序是实现以下过程的轻型设备驱动程序:

  • 在设备启动时或在驱动程序的 EVT_WDF_DRIVER_DEVICE_ADD 回调函数中:

    1. 标识它所附加到的设备。

    2. 确定驱动程序的固件版本是否比设备硬件上当前刷写的固件版本更新。

    3. 如果需要固件更新,请设置事件计时器以计划更新。

    4. 否则,在驱动程序再次启动之前不执行任何操作。

  • 在系统运行时:

    1. 如果更新已排队,请等待满足一组条件。

    2. 满足条件时,请在设备上执行固件更新。

固件更新驱动程序内容

通常,固件更新驱动程序包包含以下项:

  • 通用驱动程序 INF

  • 驱动程序目录

  • 函数驱动程序 (.sys 或 .dll)

  • 固件更新有效负载二进制文件

将固件更新包作为单独的驱动程序提交提交。

将固件更新逻辑添加到供应商提供的驱动程序

现有函数驱动程序可以实现固件更新机制,如下图所示:

使用 Windows 更新 通过现有函数驱动程序提供固件更新。

或者,如果要单独更新函数驱动程序和固件更新驱动程序,请创建另一个设备节点,你将在其中安装固件更新驱动程序。 下图显示了一个设备如何具有两个单独的设备节点:

使用 Windows 更新 通过单独的设备节点传递固件更新。

在这种情况下,函数和固件设备节点必须具有不同的硬件 ID 才能独立定位。

有几种方法可以创建第二个设备节点。 某些设备类型能够在一个物理设备(如 USB)上公开第二个设备节点。 可以使用此功能创建可由 WU 定位的设备节点,并在其中安装固件更新驱动程序。 但是,许多设备类型不允许单个物理设备枚举多个设备节点。

在这种情况下,请使用指定 AddComponent 指令的扩展 INF 来创建可通过Windows 更新目标的设备节点,并在其上安装固件更新驱动程序。 INF 文件中的以下代码片段演示了如何执行此操作:

[Manufacturer]
%Contoso%=Standard,NTamd64
[Standard.NTamd64]
%DeviceName%=Device_Install, PCI\DEVICE_ID
[Device_Install.Components]
AddComponent=ComponentName,,AddComponentSection
[AddComponentSection]
ComponentIDs = ComponentDeviceId

在上面的 INF 示例中, ComponentIDs = ComponentDeviceId 指示子设备的硬件 ID SWC\ComponentDeviceId为 。 安装后,此 INF 将创建以下设备层次结构:

父设备、主设备、AddComponent 设备。

对于将来的固件更新,请更新包含固件有效负载的 INF 和二进制文件。

将固件更新逻辑添加到 Microsoft 提供的驱动程序

若要更新使用 Microsoft 提供的驱动程序的设备固件,需要创建第二个设备节点,如上所示。

最佳做法

  • 在固件更新驱动程序 INF 中,指定 DIRID 13 ,使 PnP 将文件保留在 DriverStore 的驱动程序包中:

    [Firmware_AddReg]
    ; Store location of firmware payload
    HKR,,FirmwareFilename,,"%13%\firmware_payload.bin"
    

    PnP 在安装设备时解析此位置。 然后,驱动程序可以打开此注册表项来确定有效负载的位置。

  • 固件更新驱动程序应指定以下 INF 条目:

    Class=Firmware
    ClassGuid={f2e7dd72-6468-4e36-b6f1-6488f42c1b52}
    
  • 若要查找另一个设备节点,固件驱动程序应相对于自身遍历设备树,而不是通过枚举匹配项的所有设备节点。 用户可能已插入设备的多个实例,固件驱动程序应仅更新与之关联的设备。 通常,要查找的设备节点是安装固件驱动程序的设备节点的父级或同级节点。 例如,在具有两个设备节点的上图中,固件更新驱动程序可以查找同级设备来查找函数驱动程序。 在上图中,固件驱动程序可以查找父设备,以查找需要与之通信的主设备。

  • 驱动程序对于系统上的多个设备实例(可能具有多个不同固件版本)应是可靠的。 例如,可能有一个设备实例已连接并更新多次;然后,可能会插入一个全新的设备,其中几个旧固件版本。 这意味着状态 ((如当前版本) )必须针对设备存储,而不是存储在全局位置。

  • 如果有现有方法来更新固件 (EXE 或共同安装程序(例如) ),则在很大程度上可以在 UMDF 驱动程序中重复使用更新代码。