cros-ec: Add cros-ec-firmware

cros-ec firmware are in fmap layout, and have two sections
that this plugin will look for, the EC_RO, and EC_RW sections.

Tested using a servo_micro firmware:
$ fwupdtool firmware-parse servo_micro_v2.4.17-df61092c3.bin
<select fmap option>
FuCrosEcFirmware:
Version:                 2.4.17
  FuFirmwareImage:
  ID:                    EC_RO
  Index:                 0x1
  Version:               servo_micro_v2.4.17-df61092c3
  Data:                  0xf000
  FuFirmwareImage:
  ID:                    FR_MAIN
  Index:                 0x2
  Data:                  0xf000
  FuFirmwareImage:
  ID:                    RO_FRID
  Index:                 0x3
  Address:               0xc4
  Data:                  0x20
  FuFirmwareImage:
  ID:                    FMAP
  Index:                 0x4
  Address:               0x9a40
  Version:               1.0
  Data:                  0x15e
  FuFirmwareImage:
  ID:                    WP_RO
  Index:                 0x5
  Data:                  0x10000
  FuFirmwareImage:
  ID:                    EC_RW
  Index:                 0x6
  Address:               0x10000
  Version:               servo_micro_v2.4.17-df61092c3
  Data:                  0x10000
  FuFirmwareImage:
  ID:                    RW_FWID
  Index:                 0x7
  Address:               0x100c4
  Data:                  0x20
This commit is contained in:
Benson Leung 2020-06-16 11:22:02 -07:00 committed by Richard Hughes
parent 23ca19acf8
commit 3a02ad5129
4 changed files with 180 additions and 0 deletions

View File

@ -0,0 +1,136 @@
/*
* Copyright (C) 2020 Benson Leung <bleung@chromium.org>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include "fu-fmap-firmware.h"
#include "fu-cros-ec-common.h"
#include "fu-cros-ec-firmware.h"
#define MAXSECTIONS 2
struct _FuCrosEcFirmware {
FuFmapFirmware parent_instance;
struct cros_ec_version version;
FuCrosEcFirmwareSection sections[MAXSECTIONS];
};
G_DEFINE_TYPE (FuCrosEcFirmware, fu_cros_ec_firmware, FU_TYPE_FMAP_FIRMWARE)
static gboolean
fu_cros_ec_firmware_parse (FuFirmware *firmware,
GBytes *fw,
guint64 addr_start,
guint64 addr_end,
FwupdInstallFlags flags,
GError **error)
{
FuCrosEcFirmware *self = FU_CROS_EC_FIRMWARE (firmware);
FuFirmware *fmap_firmware = FU_FIRMWARE (firmware);
self->sections[0].name = "RO";
self->sections[1].name = "RW";
for (gsize i = 0; i < G_N_ELEMENTS (self->sections); i++) {
gboolean rw = FALSE;
FuCrosEcFirmwareSection *section = &self->sections[i];
const gchar *fmap_name;
const gchar *fmap_fwid_name;
g_autoptr(FuFirmwareImage) img = NULL;
g_autoptr(FuFirmwareImage) fwid_img = NULL;
g_autoptr(GBytes) payload_bytes = NULL;
g_autoptr(GBytes) fwid_bytes = NULL;
if (g_strcmp0 (section->name, "RO") == 0) {
fmap_name = "EC_RO";
fmap_fwid_name = "RO_FRID";
} else if (g_strcmp0 (section->name, "RW") == 0) {
rw = TRUE;
fmap_name = "EC_RW";
fmap_fwid_name = "RW_FWID";
} else {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"incorrect section name");
return FALSE;
}
img = fu_firmware_get_image_by_id (fmap_firmware,
fmap_name, error);
if (img == NULL) {
g_prefix_error (error, "%s image not found: ",
fmap_name);
return FALSE;
}
fwid_img = fu_firmware_get_image_by_id (fmap_firmware,
fmap_fwid_name, error);
if (fwid_img == NULL) {
g_prefix_error (error, "%s image not found: ",
fmap_fwid_name);
return FALSE;
}
fwid_bytes = fu_firmware_image_write (fwid_img, error);
if (fwid_bytes == NULL) {
g_prefix_error (error,
"unable to get bytes from %s: ",
fmap_fwid_name);
return FALSE;
}
if (!fu_memcpy_safe ((guint8 *) section->version,
FMAP_STRLEN, 0x0,
g_bytes_get_data (fwid_bytes, NULL),
g_bytes_get_size (fwid_bytes), 0x0,
g_bytes_get_size (fwid_bytes), error))
return FALSE;
payload_bytes = fu_firmware_image_write (img, error);
if (payload_bytes == NULL) {
g_prefix_error (error,
"unable to get bytes from %s: ",
fmap_name);
return FALSE;
}
section->offset = fu_firmware_image_get_addr (img);
section->size = g_bytes_get_size (payload_bytes);
fu_firmware_image_set_version (img, section->version);
if (rw) {
if (!fu_cros_ec_parse_version (section->version,
&self->version,
error)) {
g_prefix_error (error,
"failed parsing firmware's version: %32s: ",
section->version);
return FALSE;
}
fu_firmware_set_version (firmware,
self->version.triplet);
}
}
/* success */
return TRUE;
}
static void
fu_cros_ec_firmware_init (FuCrosEcFirmware *self)
{
}
static void
fu_cros_ec_firmware_class_init (FuCrosEcFirmwareClass *klass)
{
FuFmapFirmwareClass *klass_firmware = FU_FMAP_FIRMWARE_CLASS (klass);
klass_firmware->parse = fu_cros_ec_firmware_parse;
}
FuFirmware *
fu_cros_ec_firmware_new (void)
{
return g_object_new (FU_TYPE_CROS_EC_FIRMWARE, NULL);
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2020 Benson Leung <bleung@chromium.org>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include "fu-firmware.h"
#include "fu-fmap-firmware.h"
#define FU_TYPE_CROS_EC_FIRMWARE (fu_cros_ec_firmware_get_type ())
G_DECLARE_FINAL_TYPE (FuCrosEcFirmware, fu_cros_ec_firmware, FU, CROS_EC_FIRMWARE, FuFmapFirmware)
/*
* Each RO or RW section of the new image can be in one of the following
* states.
*/
typedef enum {
FU_CROS_EC_FW_NOT_NEEDED= 0, /* Version below or equal that on the target. */
FU_CROS_EC_FW_NOT_POSSIBLE, /*
* RO is newer, but can't be transferred due to
* target RW shortcomings.
*/
FU_CROS_EC_FW_NEEDED /*
* This section needs to be transferred to the
* target.
*/
} FuCrosEcFirmwareUpgradeStatus;
typedef struct {
const gchar *name;
guint32 offset;
gsize size;
FuCrosEcFirmwareUpgradeStatus ustatus;
gchar version[FMAP_STRLEN];
gint32 rollback;
guint32 key_version;
} FuCrosEcFirmwareSection;
FuFirmware *fu_cros_ec_firmware_new (void);

View File

@ -10,10 +10,12 @@
#include "fu-hash.h"
#include "fu-cros-ec-usb-device.h"
#include "fu-cros-ec-firmware.h"
void
fu_plugin_init (FuPlugin *plugin)
{
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
fu_plugin_set_device_gtype (plugin, FU_TYPE_CROS_EC_USB_DEVICE);
fu_plugin_add_firmware_gtype (plugin, "cros-ec", FU_TYPE_CROS_EC_FIRMWARE);
}

View File

@ -10,6 +10,7 @@ shared_module('fu_plugin_cros_ec',
'fu-plugin-cros-ec.c',
'fu-cros-ec-usb-device.c',
'fu-cros-ec-common.c',
'fu-cros-ec-firmware.c',
],
include_directories : [
root_incdir,