Permalink
Browse files

nvme: Add flag to support manually aligning the firmware to the FWUG …

…value

This is required for drives from Phison.
  • Loading branch information...
hughsie committed Jan 15, 2019
1 parent d5f0da1 commit fc90f3954e25749270a91fd4551b417bfee66b3d
Showing with 61 additions and 1 deletion.
  1. +1 −0 plugins/nvme/README.md
  2. +10 −1 plugins/nvme/fu-nvme-device.c
  3. +6 −0 plugins/nvme/meson.build
  4. +3 −0 plugins/nvme/nvme.quirk
  5. +38 −0 src/fu-common.c
  6. +3 −0 src/fu-common.h
@@ -44,3 +44,4 @@ This plugin uses the following plugin-specific quirks:
| Quirk | Description | Minimum fwupd version |
|------------------------|---------------------------------------------|-----------------------|
| `NvmeBlockSize` | The block size used for NVMe writes | 1.1.3 |
| `Flags` | `force-align` if image should be padded | 1.2.4 |
@@ -410,12 +410,21 @@ static gboolean
fu_nvme_device_write_firmware (FuDevice *device, GBytes *fw, GError **error)
{
FuNvmeDevice *self = FU_NVME_DEVICE (device);
g_autoptr(GBytes) fw2 = NULL;
g_autoptr(GPtrArray) chunks = NULL;
guint64 block_size = self->write_block_size > 0 ?
self->write_block_size : 0x1000;

/* some vendors provide firmware files whose sizes are not multiples
* of blksz *and* the device won't accept blocks of different sizes */
if (fu_device_has_custom_flag (device, "force-align")) {
fw2 = fu_common_bytes_align (fw, block_size, 0xff);
} else {
fw2 = g_bytes_ref (fw);
}

/* build packets */
chunks = fu_chunk_array_new_from_bytes (fw,
chunks = fu_chunk_array_new_from_bytes (fw2,
0x00, /* start_addr */
0x00, /* page_sz */
block_size); /* block size */
@@ -1,5 +1,11 @@
cargs = ['-DG_LOG_DOMAIN="FuPluginNvme"']

install_data([
'nvme.quirk',
],
install_dir: join_paths(datadir, 'fwupd', 'quirks.d')
)

shared_module('fu_plugin_nvme',
sources : [
'fu-plugin-nvme.c',
@@ -0,0 +1,3 @@
# Phison
[DeviceInstanceId=NVME\VEN_1987]
Flags = force-align
@@ -1175,3 +1175,41 @@ fu_common_dump_bytes (const gchar *log_domain,
const guint8 *data = g_bytes_get_data (bytes, &len);
fu_common_dump_raw (log_domain, title, data, len);
}

/**
* fu_common_bytes_align:
* @bytes: a #GBytes
* @blksz: block size in bytes
* @padval: the byte used to pad the byte buffer
*
* Aligns a block of memory to @blksize using the @padval value; if
* the block is already aligned then the original @bytes is returned.
*
* Returns: (transfer full): a #GBytes, possibly @bytes
*
* Since: 1.2.4
**/
GBytes *
fu_common_bytes_align (GBytes *bytes, gsize blksz, gchar padval)
{
const guint8 *data;
gsize sz;

g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (blksz > 0, NULL);

/* pad */
data = g_bytes_get_data (bytes, &sz);
if (sz % blksz != 0) {
gsize sz_align = ((sz / blksz) + 1) * blksz;
guint8 *data_align = g_malloc (sz_align);
memcpy (data_align, data, sz);
memset (data_align + sz, padval, sz_align - sz);
g_debug ("aligning 0x%x bytes to 0x%x",
(guint) sz, (guint) sz_align);
return g_bytes_new_take (data_align, sz_align);
}

/* perfectly aligned */
return g_bytes_ref (bytes);
}
@@ -86,6 +86,9 @@ void fu_common_dump_full (const gchar *log_domain,
void fu_common_dump_bytes (const gchar *log_domain,
const gchar *title,
GBytes *bytes);
GBytes *fu_common_bytes_align (GBytes *bytes,
gsize blksz,
gchar padval);

typedef guint FuEndianType;

0 comments on commit fc90f39

Please sign in to comment.