Introduction

When fwupd starts it enumerates all PCI and USB hardware and generates Instance IDs based on the reported vendor and product so that it can match the device to a plugin. The plugin knows how to communicate with the device (for instance using vendor-specific USB control transfers) and also knows how to parse the firmware and deliver it to the device.

Before a vendor can ship a firmware on the LVFS to a machine using Linux (or ChromeOS) the fwupd package often must be updated so that it knows what plugin to use for that specific device. At this point other overridden quirk data can also be set. For instance, the icon, long summary or even per-plugin flags that change device behavior. For example colorhug.quirk:

[USB\VID_273F&PID_1001]
Plugin = colorhug
Flags = self-recovery
Icon = colorimeter-colorhug

Updating the fwupd binary package might take anywhere from a few weeks to several years due to various Linux distribution policies. Clearly this isn’t good when the majority of firmware updates are distributed to address security issues.

One suggestion would be to put this quirk information into the existing update metadata provided by the configured remote, but this has several problems:

  • The daemon needs to enumerate hardware that does not have updates on the main LVFS remote.
  • A lot of machines using fwupd have never connected to the internet and we still want to enumerate hardware for audit and verification purposes.
  • Re-enumerating all physical hardware (to get the latest quirks) when updating the metadata is not straightforward.
  • The VID/PID is not necessarily the information that the plugin matches to assign the firmware stream, and so this would have to be a separate facet of metadata — which may have to include quirks too.

Matching devices to plugins should be thought of as orthogonal to matching firmware to devices. To simplify deployment it should be possible to allow the device itself to specify the plugin to use and optionally additional quirk data.

Specification

Devices that implement a fwupd BOS DS20 descriptor can be updated without always needing to update the runtime version of fwupd for updated quirk entries, assuming the device is updatable by the existing vendor plugin.

USB devices can create a new platform device capability BOS “Binary Object Store” descriptor with bDevCapabilityType=0x05 and a fwupd-specific UUID, specifically 010aec63-f574-52cd-9dda-2852550d94f0. This UUID is generated type-5 SHA-1 hash of the word fwupd using a DNS namespace. Using this custom UUID will ensure that Microsoft Windows does not try to parse the capability descriptor as a Microsoft OS 2.0 descriptor set.

Implementation

Create a BOS DS20 descriptor such as:

1C 10 05 00 63 ec 0a 01 74 f5 cd 52 9d da 28 52 55 0d 94 f0 05 08 01 00 20 00 2a 00
├┘ ├┘ ├┘ ├┘ └─────────────┬───────────────────────────────┘ └─┬───────┘ └─┬─┘ ├┘ ├┘
│  │  │  │                └─PlatformCapabilityUUID            │   wLength─┘   │  │
│  │  │  └─bReserved                                dwVersion─┘   bVendorCode─┘  │
│  │  └────bDevCapability                                         bAltEnumCmd────┘
│  └───────bDescriptorType
└──────────bLength

The dwVersion encoded here is fwupd 1.8.5, which is also the first version that supports BOS DS20 descriptors.

The BOS descriptors are sorted by the requester and can appear in any order. The descriptor with the highest dwVersion that is not newer than the current running daemon version is used. This means that dwVersion is effectively the minimum version of fwupd that should read the descriptor. This allows devices to set different quirks depending on the fwupd version, although in practice this should not be required. A suitable bVendorCode should be chosen that is not used for existing device operation.

  • The dwVersion parameter must be larger than 0x00010805, i.e. 1.8.5.
  • The bAltEnumCmd parameter must be zero.
  • The PlatformCapabilityUUID must be 010aec63-f574-52cd-9dda-2852550d94f0.

Then allow the device to reply to a USB control request with the following parameters:

transfer-direction: device-to-host
request-type: vendor
recipient: device
bRequest: {value of bVendorCode in the BOS descriptor}
wValue: 0x00
wIndex: 0x07
wLength: {value of wLength in the BOS descriptor}

The device should return something like:

50 6c 75 67 69 6e 3d 64 66 75 0a 49 63 6f 6e 3d 63 6f 6d 70 75 74 65 72 0a 00 00 00 00 00 00 00

…which is the UTF-8 quirk data, e.g.

Plugin=dfu
Icon=computer

The UTF-8 quirk data must not contain Windows CRLF-style line endings.

Workflow

To generate the fwupd DS20 descriptor save a file such as fw-ds20.builder.xml:

<firmware gtype="FuUsbDeviceFwDs20">
  <idx>42</idx>   <!-- bVendorCode -->
  <size>32</size> <!-- wLength -->
</firmware>

Then run fwupdtool firmware-build fw-ds20.builder.xml fw-ds20.bin.

To generate the control transfer response, save a file such as fw-ds20.quirk:

[USB\VID_273F&PID_1004]
Plugin = dfu
Icon = computer

Then run contrib/generate-ds20.py fw-ds20.quirk --bufsz 32. The maximum buffer size is typically hardcoded for the device and may be specified in a microcontroller datasheet.

Prior Art

Hardcoded Class & Subclass

The fwupd project already support two plugins that use the USB class code, rather than the exact instance ID with the VID/PID. For example, this DFU entry means “match any USB device with class 0xFE (application specific) and subclass 0x01”:

[USB\CLASS_FE&SUBCLASS_01]
Plugin = dfu

These kind of devices do not need any device to plugin mapping (although, they still might need a quirk if they are non-complaint in some way, for example needing Flags = detach-for-attach) – but in the most cases they just work.

The same can be done for Fastboot devices, matching class 0xFF (vendor specific), subclass 0x42 and protocol 0x03, although there is the same caveat for non-compliant devices that need quirk entries like FastbootOperationDelay = 250:

[USB\CLASS_FF&SUBCLASS_42&PROT_03]
Plugin = fastboot

Microsoft OS Descriptors 1.0

The Microsoft OS Descriptors 1.0 Specification defines a device-specific variable-length metadata block of CompatibleID:SubCompatibleID on a string index of 0xEE where the CompatibleID and SubCompatibleID are also both hardcoded at 8 bytes.

Using FWUPDPLU or FWUPDFLA as the CompatibleID would be acceptable, but we could not fit the plugin name (e.g. logitech-bulkcontroller) or the GUID (16 bytes) in an 8 byte SubCompatibleID. Some non-compliant devices also hang and stop working when probing this specific string index.

Microsoft OS Descriptors 2.0

The Microsoft OS Descriptors 2.0 Specification is more useful as it defines a new device capability that can return a variable length vendor-defined section of data, using a UUID as a key. Using the BOS “Binary Object Store” descriptor is only available for devices using USB specification version 2.1 and newer. The BOS descriptor is used for Wireless USB details, USB 2.0 extensions, SuperSpeed USB connection details and a Container ID.

The BOS descriptor does give the OS the ability to parse the platform capability, which is bDevCapabilityType=0x05. For UUID D8DD60DF-4589-4CC7-9CD2-659D9E648A9F this is identified as a structured blob of data Microsoft Windows uses for the suspend mode of the device.

Creating a new bDevCapabilityType would allow vendors to store a binary blob (e.g. Plugin=foobarbaz\nFlags=QuirkValueHere\n) but that would be out-of-specification and difficult to implement.