Plugin: CFU - Component Firmware Update

Introduction

CFU is a protocol from Microsoft to make it easy to install firmware on HID devices.

See https://docs.microsoft.com/en-us/windows-hardware/drivers/cfu/cfu-specification for more details.

This plugin supports the following protocol ID:

  • com.microsoft.cfu

Implementation Notes

CFU has a pre-download phase that is used to send the firmware offer to the microcontroller, so the device can check if the firmware is required and compatible.

CFU also requires devices to be able to transfer the entire new transfer mode in runtime mode. The pre-download “offer” allows the device to check any sub-components attached (e.g. other devices attached to the SoC) and forces it to do dependency resolution in case sub-components have to be updated in a specific order.

Pushing the dependency resolution down to the device means the low-power device has to do all the version comparisons and also know all the logic with regard to protocol incompatibilities. The end-user could be in a position where the device firmware needs to be updated so that it “knows” about the new protocol restrictions, which are needed to update the device and the things attached in the right order in a subsequent update. If the user always updates the device to the latest version, the factory-default running version might yet know about the new restrictions. It is therefore imperative that all previous versions are tested being updated from.

Something that we support in fwupd is being able to restrict the peripheral device firmware to a specific SMBIOS CHID or a system firmware vendor, which lets vendors solve the same hardware in different chassis, with custom firmware problem. Using CFU in Microsoft Windows also means that the peripheral is unaware of the other devices in the system, so for instance couldn’t only install a new firmware version for only new builds of Windows for example.

A few other consideration for vendors is the doubling of flash storage required to do an runtime transfer, the extra power budget of being woken up to process the offer and providing enough bulk power to stay alive if unplugged during a A/B swap. On most existing hardware the easiest way to implement CFU is an additional ARM micro-controller to act as a CFU “bridge” for legacy silicon. The CFU “bridge” could also do signing and encryption. CFU does not define any standard way to encrypt and sign firmware, or to detect if devices have any firmware verification capabilities and so this too will need to be set per-device either in the metadata or in the quirk file.

CFU also downloads in the runtime mode in the background, at a maximum of 52 bytes per HID request and response. This means even small updates will take a long time to complete due to the huge number of USB control transfers required. The specification also doesn’t specify the HID reports to use, so it all needs to be hardcoded per-device unless the exact same defaults are used as in CFU/Tools/ComponentFirmwareUpdateStandAloneToolSample/protocolCfgExample.cfg.

In fwupd these can be set as quirks in cfu.quirk.

The included https://github.com/fwupd/fwupd/blob/main/contrib/cfu-inf-to-quirk.py script may be useful to convert an existing .inf file to fwupd .quirk format.

Firmware Format

Due to the one-shot way fwupd deploys firmware, the daemon only deals with one “payload” per update. The offer and payload currently have to be combined in an archive where they are transferred to the device one after the other.

The files in the firmware archive therefore should have the extensions .offer.bin and .payload.bin.

GUID Generation

These devices use standard USB DeviceInstanceId values, as well as two extra for the component ID and the bank, e.g.

  • HIDRAW\VEN_17EF&DEV_7226&CID_01&BANK_1
  • HIDRAW\VEN_17EF&DEV_7226&CID_01
  • HIDRAW\VEN_17EF&DEV_7226

Quirk Use

This plugin uses the following plugin-specific quirks:

CfuVersionGetReport

The HID report usage to use when parsing the response of GET_FIRMWARE_VERSION.

This usually corresponds to the VersionsFeatureValueCapabilityUsageRangeMinimum value set in the .inf file.

Since: 1.9.1

CfuOfferSetReport

The HID report usage to use when sending the request for FIRMWARE_UPDATE_OFFER.

This usually corresponds to the OfferOutputValueCapabilityUsageRangeMinimum value set in the .inf file.

Since: 1.9.1

CfuOfferGetReport

The HID report usage to use when parsing the response of FIRMWARE_UPDATE_OFFER.

This usually corresponds to the OfferInputValueCapabilityUsageRangeMinimum value set in the .inf file.

Since: 1.9.1

CfuContentSetReport

The HID report usage to use when sending the request for FIRMWARE_UPDATE_CONTENT.

This usually corresponds to the PayloadOutputValueCapabilityUsageRangeMinimum value set in the .inf file.

Since: 1.9.1

CfuContentGetReport

The HID report usage to use when parsing the response of FIRMWARE_UPDATE_CONTENT.

This usually corresponds to the PayloadInputValueCapabilityUsageRangeMinimum value set in the .inf file.

Since: 1.9.1

Update Behavior

The device has to support runtime updates and does not have a detach-into-bootloader mode — but after the install has completed the device still has to reboot into the new firmware.

Vendor ID Security

The vendor ID is set from the USB vendor, in this instance set to HIDRAW:0x17EF

External Interface Access

This plugin requires read/write access to /dev/bus/usb.

Version Considerations

This plugin has been available since fwupd version 1.7.1.