trivial: Allow setting the firmware min and max sizes from quirk files

This commit is contained in:
Richard Hughes 2018-08-27 21:24:27 +01:00
parent a62618303f
commit a417d6c82a
8 changed files with 212 additions and 29 deletions

View File

@ -3,6 +3,8 @@
Plugin = colorhug
Flags = is-bootloader
Guid = 40338ceb-b966-4eae-adae-9c32edfcc484
FirmwareSizeMin = 0x2000
FirmwareSizeMax = 0x8000
[DeviceInstanceId=USB\VID_273F&PID_1001]
Plugin = colorhug
Flags = none
@ -17,6 +19,8 @@ Flags = none
Summary = An open source display colorimeter
Icon = colorimeter-colorhug
Guid = 2082b5e0-7a64-478a-b1b2-e3404fab6dad
FirmwareSizeMin = 0x2000
FirmwareSizeMax = 0x8000
[DeviceInstanceId=USB\VID_273F&PID_1005]
Plugin = colorhug
Flags = is-bootloader
@ -28,6 +32,8 @@ Plugin = colorhug
Flags = halfsize,none
Summary = An open source ambient light sensor
Guid = 84f40464-9272-4ef7-9399-cd95f12da696
FirmwareSizeMin = 0x1000
FirmwareSizeMax = 0x4000
[DeviceInstanceId=USB\VID_273F&PID_1006]
Plugin = colorhug
Flags = halfsize,is-bootloader

View File

@ -437,25 +437,16 @@ _dfu_firmware_get_default_element_data (DfuFirmware *firmware)
return dfu_element_get_contents (element);
}
static gboolean
fu_csr_device_download (FuDevice *device, GBytes *blob, GError **error)
static GBytes *
fu_csr_device_prepare_firmware (FuDevice *device, GBytes *fw, GError **error)
{
FuCsrDevice *self = FU_CSR_DEVICE (device);
GBytes *blob_noftr;
const guint8 *data;
gsize sz = 0;
guint16 idx;
g_autoptr(DfuFirmware) dfu_firmware = dfu_firmware_new ();
g_autoptr(GBytes) blob_empty = NULL;
g_autoptr(GPtrArray) chunks = NULL;
/* notify UI */
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
/* parse the file */
if (!dfu_firmware_parse_data (dfu_firmware, blob,
if (!dfu_firmware_parse_data (dfu_firmware, fw,
DFU_FIRMWARE_PARSE_FLAG_NONE, error))
return FALSE;
return NULL;
if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) {
g_autofree gchar *fw_str = NULL;
fw_str = dfu_firmware_to_string (dfu_firmware);
@ -466,7 +457,7 @@ fu_csr_device_download (FuDevice *device, GBytes *blob, GError **error)
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"expected DFU firmware");
return FALSE;
return NULL;
}
/* get the blob from the firmware file */
@ -476,13 +467,27 @@ fu_csr_device_download (FuDevice *device, GBytes *blob, GError **error)
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"firmware contained no data");
return FALSE;
return NULL;
}
/* success */
return g_bytes_ref (blob_noftr);
}
static gboolean
fu_csr_device_download (FuDevice *device, GBytes *blob, GError **error)
{
FuCsrDevice *self = FU_CSR_DEVICE (device);
guint16 idx;
g_autoptr(GBytes) blob_empty = NULL;
g_autoptr(GPtrArray) chunks = NULL;
/* notify UI */
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
/* create chunks */
data = g_bytes_get_data (blob_noftr, &sz);
chunks = fu_chunk_array_new (data, (guint32) sz, 0x0, 0x0,
FU_CSR_PACKET_DATA_SIZE - FU_CSR_COMMAND_HEADER_SIZE);
chunks = fu_chunk_array_new_from_bytes (blob, 0x0, 0x0,
FU_CSR_PACKET_DATA_SIZE - FU_CSR_COMMAND_HEADER_SIZE);
/* send to hardware */
for (idx = 0; idx < chunks->len; idx++) {
@ -576,6 +581,7 @@ fu_csr_device_class_init (FuCsrDeviceClass *klass)
klass_device->to_string = fu_csr_device_to_string;
klass_device->write_firmware = fu_csr_device_download;
klass_device->read_firmware = fu_csr_device_upload;
klass_device->prepare_firmware = fu_csr_device_prepare_firmware;
klass_device->attach = fu_csr_device_attach;
klass_usb_device->open = fu_csr_device_open;
klass_usb_device->close = fu_csr_device_close;

View File

@ -899,15 +899,6 @@ lu_device_write_firmware (FuDevice *device, GBytes *fw, GError **error)
g_return_val_if_fail (LU_IS_DEVICE (device), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
/* corrupt */
if (g_bytes_get_size (fw) < 0x4000) {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"firmware is too small");
return FALSE;
}
/* call device-specific method */
if (klass->write_firmware == NULL) {
g_set_error (error,

View File

@ -1,5 +1,11 @@
cargs = ['-DG_LOG_DOMAIN="FuPluginUnifying"']
install_data([
'unifying.quirk',
],
install_dir: join_paths(datadir, 'fwupd', 'quirks.d')
)
shared_module('fu_plugin_unifying',
sources : [
'fu-plugin-unifying.c',

View File

@ -0,0 +1,19 @@
# Nordic
[DeviceInstanceId=USB\VID_046D&PID_AAAA]
Plugin = unifying
FirmwareSizeMin = 0x4000
# Nordic Pico
[DeviceInstanceId=USB\VID_046D&PID_AAAE]
Plugin = unifying
FirmwareSizeMin = 0x4000
# Nordic
[DeviceInstanceId=USB\VID_046D&PID_AAAC]
Plugin = unifying
FirmwareSizeMin = 0x4000
# Nordic Pico
[DeviceInstanceId=USB\VID_046D&PID_AAAD]
Plugin = unifying
FirmwareSizeMin = 0x4000

View File

@ -41,6 +41,8 @@ typedef struct {
guint order;
guint priority;
gboolean done_probe;
guint64 size_min;
guint64 size_max;
} FuDevicePrivate;
enum {
@ -549,6 +551,14 @@ fu_device_add_guid_quirks (FuDevice *device, const gchar *guid)
if (tmp != NULL)
fu_device_add_parent_guid (device, tmp);
/* firmware size */
tmp = fu_quirks_lookup_by_guid (priv->quirks, guid, FU_QUIRKS_FIRMWARE_SIZE_MIN);
if (tmp != NULL)
fu_device_set_firmware_size_min (device, fu_common_strtoull (tmp));
tmp = fu_quirks_lookup_by_guid (priv->quirks, guid, FU_QUIRKS_FIRMWARE_SIZE_MAX);
if (tmp != NULL)
fu_device_set_firmware_size_max (device, fu_common_strtoull (tmp));
/* children */
tmp = fu_quirks_lookup_by_guid (priv->quirks, guid, FU_QUIRKS_CHILDREN);
if (tmp != NULL) {
@ -563,6 +573,40 @@ fu_device_add_guid_quirks (FuDevice *device, const gchar *guid)
}
}
/**
* fu_device_set_firmware_size_min:
* @device: A #FuDevice
* @size_min: Size in bytes
*
* Sets the minimum allowed size of the firmware blob.
*
* Since: 1.1.2
**/
void
fu_device_set_firmware_size_min (FuDevice *device, guint64 size_min)
{
FuDevicePrivate *priv = GET_PRIVATE (device);
g_return_if_fail (FU_IS_DEVICE (device));
priv->size_min = size_min;
}
/**
* fu_device_set_firmware_size_max:
* @device: A #FuDevice
* @size_min: Size in bytes
*
* Sets the maximum allowed size of the firmware blob.
*
* Since: 1.1.2
**/
void
fu_device_set_firmware_size_max (FuDevice *device, guint64 size_max)
{
FuDevicePrivate *priv = GET_PRIVATE (device);
g_return_if_fail (FU_IS_DEVICE (device));
priv->size_max = size_max;
}
static void
fu_device_add_guid_safe (FuDevice *device, const gchar *guid)
{
@ -1169,6 +1213,14 @@ fu_device_to_string (FuDevice *device)
fwupd_pad_kv_str (str, "AlternateId", priv->alternate_id);
if (priv->equivalent_id != NULL)
fwupd_pad_kv_str (str, "EquivalentId", priv->equivalent_id);
if (priv->size_min > 0) {
g_autofree gchar *sz = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->size_min);
fwupd_pad_kv_str (str, "FirmwareSizeMin", sz);
}
if (priv->size_max > 0) {
g_autofree gchar *sz = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->size_max);
fwupd_pad_kv_str (str, "FirmwareSizeMax", sz);
}
keys = g_hash_table_get_keys (priv->metadata);
for (GList *l = keys; l != NULL; l = l->next) {
const gchar *key = l->data;
@ -1258,6 +1310,7 @@ gboolean
fu_device_write_firmware (FuDevice *device, GBytes *fw, GError **error)
{
FuDeviceClass *klass = FU_DEVICE_GET_CLASS (device);
g_autoptr(GBytes) fw_new = NULL;
g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@ -1271,8 +1324,78 @@ fu_device_write_firmware (FuDevice *device, GBytes *fw, GError **error)
return FALSE;
}
/* prepare (e.g. decompress) firmware */
fw_new = fu_device_prepare_firmware (device, fw, error);
if (fw_new == NULL)
return FALSE;
/* call vfunc */
return klass->write_firmware (device, fw, error);
return klass->write_firmware (device, fw_new, error);
}
/**
* fu_device_prepare_firmware:
* @device: A #FuDevice
* @fw: A #GBytes
* @error: A #GError
*
* Prepares the firmware by calling an optional device-specific vfunc for the
* device, which can do things like decompressing or parsing of the firmware
* data.
*
* For all firmware, this checks the size of the firmware if limits have been
* set using fu_device_set_firmware_size_min(), fu_device_set_firmware_size_max()
* or using a quirk entry.
*
* Returns: (return full): A new #GBytes, or %NULL for error
*
* Since: 1.1.2
**/
GBytes *
fu_device_prepare_firmware (FuDevice *device, GBytes *fw, GError **error)
{
FuDeviceClass *klass = FU_DEVICE_GET_CLASS (device);
FuDevicePrivate *priv = GET_PRIVATE (device);
guint64 fw_sz;
g_autoptr(GBytes) fw_new = NULL;
g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
g_return_val_if_fail (fw != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
/* optionally subclassed */
if (klass->prepare_firmware != NULL) {
fw_new = klass->prepare_firmware (device, fw, error);
if (fw_new == NULL)
return FALSE;
} else {
fw_new = g_bytes_ref (fw);
}
/* check size */
fw_sz = (guint64) g_bytes_get_size (fw_new);
if (priv->size_max > 0 && fw_sz > priv->size_max) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"firmware is %04x bytes larger than the allowed "
"maximum size of %04x bytes",
(guint) (fw_sz - priv->size_max),
(guint) priv->size_max);
return FALSE;
}
if (priv->size_min > 0 && fw_sz < priv->size_min) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"firmware is %04x bytes smaller than the allowed "
"minimum size of %04x bytes",
(guint) (priv->size_min - fw_sz),
(guint) priv->size_max);
return FALSE;
}
return g_steal_pointer (&fw_new);
}
/**

View File

@ -37,8 +37,11 @@ struct _FuDeviceClass
GError **error);
gboolean (*probe) (FuDevice *device,
GError **error);
GBytes *(*prepare_firmware) (FuDevice *device,
GBytes *fw,
GError **error);
/*< private >*/
gpointer padding[25];
gpointer padding[24];
};
/**
@ -157,6 +160,10 @@ void fu_device_set_remove_delay (FuDevice *device,
FwupdStatus fu_device_get_status (FuDevice *device);
void fu_device_set_status (FuDevice *device,
FwupdStatus status);
void fu_device_set_firmware_size_min (FuDevice *device,
guint64 size_min);
void fu_device_set_firmware_size_max (FuDevice *device,
guint64 size_max);
guint fu_device_get_progress (FuDevice *device);
void fu_device_set_progress (FuDevice *device,
guint progress);
@ -170,6 +177,9 @@ FwupdRelease *fu_device_get_release_default (FuDevice *device);
gboolean fu_device_write_firmware (FuDevice *device,
GBytes *fw,
GError **error);
GBytes *fu_device_prepare_firmware (FuDevice *device,
GBytes *fw,
GError **error);
GBytes *fu_device_read_firmware (FuDevice *device,
GError **error);
gboolean fu_device_attach (FuDevice *device,

View File

@ -181,6 +181,28 @@ gchar *fu_quirks_lookup_by_guids (FuQuirks *self,
*/
#define FU_QUIRKS_VENDOR "Vendor"
/**
* FU_QUIRKS_FIRMWARE_SIZE_MIN:
* @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806`
* @value: the vendor, e.g. `0x10000`
*
* Sets the minimum allowed firmware size.
*
* Since: 1.1.2
*/
#define FU_QUIRKS_FIRMWARE_SIZE_MIN "FirmwareSizeMin"
/**
* FU_QUIRKS_FIRMWARE_SIZE_MAX:
* @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806`
* @value: the vendor, e.g. `0x10000`
*
* Sets the maximum allowed firmware size.
*
* Since: 1.1.2
*/
#define FU_QUIRKS_FIRMWARE_SIZE_MAX "FirmwareSizeMax"
G_END_DECLS
#endif /* __FU_QUIRKS_H */