From 0573febb0b69646925e574f612262149c7e4a5cf Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 22 Mar 2019 12:11:22 +0000 Subject: [PATCH] superio: Add support for reading the device checksum --- plugins/superio/fu-plugin-superio.c | 48 ++++++++++ plugins/superio/fu-superio-common.h | 21 ++++ plugins/superio/fu-superio-it89-device.c | 117 +++++++++++++++++++++++ 3 files changed, 186 insertions(+) diff --git a/plugins/superio/fu-plugin-superio.c b/plugins/superio/fu-plugin-superio.c index 7381e2888..66e6bb6fd 100644 --- a/plugins/superio/fu-plugin-superio.c +++ b/plugins/superio/fu-plugin-superio.c @@ -105,3 +105,51 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) } return TRUE; } + +gboolean +fu_plugin_verify_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_attach (device, error); +} + +gboolean +fu_plugin_verify_detach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_detach (device, error); +} + +gboolean +fu_plugin_verify (FuPlugin *plugin, FuDevice *device, + FuPluginVerifyFlags flags, GError **error) +{ + g_autoptr(GBytes) fw = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + GChecksumType checksum_types[] = { + G_CHECKSUM_SHA1, + G_CHECKSUM_SHA256, + 0 }; + + /* get data */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + fw = fu_device_read_firmware (device, error); + if (fw == NULL) + return FALSE; + for (guint i = 0; checksum_types[i] != 0; i++) { + g_autofree gchar *hash = NULL; + hash = g_compute_checksum_for_bytes (checksum_types[i], fw); + fu_device_add_checksum (device, hash); + } + return TRUE; +} diff --git a/plugins/superio/fu-superio-common.h b/plugins/superio/fu-superio-common.h index 54274c152..c7d0d2ce8 100644 --- a/plugins/superio/fu-superio-common.h +++ b/plugins/superio/fu-superio-common.h @@ -35,6 +35,27 @@ G_BEGIN_DECLS #define SIO_DEPTH2_I2EC_ADDRH 0x11 #define SIO_DEPTH2_I2EC_DATA 0x12 +/* + * The PMC is a communication channel used between the host and the EC. + * Compatible mode uses four registers: + * + * Name | EC | HOST | ADDR + * _____________________|_______________|_______________|______ + * PMDIR | RO | WO | 0x62 + * PMDOR | WO | RO | 0x62 + * PMCMDR | RO | RO | 0x66 + * PMSTR | RO | RO | 0x66 + */ +#define SIO_EC_PMC_PM1STS 0x00 +#define SIO_EC_PMC_PM1DO 0x01 +#define SIO_EC_PMC_PM1DOSCI 0x02 +#define SIO_EC_PMC_PM1DOCMI 0x03 +#define SIO_EC_PMC_PM1DI 0x04 +#define SIO_EC_PMC_PM1DISCI 0x05 +#define SIO_EC_PMC_PM1CTL 0x06 +#define SIO_EC_PMC_PM1IC 0x07 +#define SIO_EC_PMC_PM1IE 0x08 + /* SPI commands */ #define SIO_SPI_CMD_READ 0x03 #define SIO_SPI_CMD_HS_READ 0x0b diff --git a/plugins/superio/fu-superio-it89-device.c b/plugins/superio/fu-superio-it89-device.c index 6a7d8c4b2..bc3f65700 100644 --- a/plugins/superio/fu-superio-it89-device.c +++ b/plugins/superio/fu-superio-it89-device.c @@ -121,6 +121,122 @@ fu_superio_it89_device_setup (FuSuperioDevice *self, GError **error) return TRUE; } +static gboolean +fu_superio_it89_device_ec_pm1do_sci (FuSuperioDevice *self, guint8 val, GError **error) +{ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DOSCI, error)) + return FALSE; + if (!fu_superio_device_ec_write1 (self, val, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_superio_it89_device_ec_pm1do_smi (FuSuperioDevice *self, guint8 val, GError **error) +{ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DOCMI, error)) + return FALSE; + if (!fu_superio_device_ec_write1 (self, val, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_superio_device_ec_read_status (FuSuperioDevice *self, GError **error) +{ + guint8 tmp = 0x00; + + /* read status register */ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_sci (self, SIO_SPI_CMD_RDSR, error)) + return FALSE; + + /* wait for write */ + do { + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DI, error)) + return FALSE; + if (!fu_superio_device_ec_read (self, &tmp, error)) + return FALSE; + } while ((tmp & SIO_STATUS_EC_OBF) != 0); + + /* watch SCI events */ + return fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DISCI, error); +} + +static GBytes * +fu_superio_it89_device_read_addr (FuSuperioDevice *self, + guint32 addr, + guint size, + GFileProgressCallback progress_cb, + GError **error) +{ + g_autofree guint8 *buf = NULL; + + /* check... */ + if (!fu_superio_device_ec_read_status (self, error)) + return NULL; + + /* high speed read */ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return NULL; + if (!fu_superio_it89_device_ec_pm1do_sci (self, SIO_SPI_CMD_HS_READ, error)) + return NULL; + + /* set address, MSB, MID, LSB */ + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr >> 16, error)) + return NULL; + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr >> 8, error)) + return NULL; + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr & 0xff, error)) + return NULL; + + /* padding for HS? */ + if (!fu_superio_it89_device_ec_pm1do_smi (self, 0x0, error)) + return NULL; + + /* read out data */ + buf = g_malloc0 (size); + for (guint i = 0; i < size; i++) { + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DI, error)) + return NULL; + if (!fu_superio_device_ec_read (self, &buf[i], error)) + return NULL; + + /* update progress */ + if (progress_cb != NULL) + progress_cb ((goffset) i, (goffset) size, self); + } + + /* check again... */ + if (!fu_superio_device_ec_read_status (self, error)) + return NULL; + + /* success */ + return g_bytes_new_take (g_steal_pointer (&buf), size); +} + +static void +fu_superio_it89_device_progress_cb (goffset current, goffset total, gpointer user_data) +{ + FuDevice *device = FU_DEVICE (user_data); + fu_device_set_progress_full (device, (gsize) current, (gsize) total); +} + +static GBytes * +fu_superio_it89_device_read_firmware (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + guint64 fwsize = fu_device_get_firmware_size_min (device); + g_autoptr(GBytes) blob = NULL; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + blob = fu_superio_it89_device_read_addr (self, 0x0, fwsize, + fu_superio_it89_device_progress_cb, + error); + return g_steal_pointer (&blob); +} + static gboolean fu_superio_it89_device_attach (FuDevice *device, GError **error) { @@ -172,5 +288,6 @@ fu_superio_it89_device_class_init (FuSuperioIt89DeviceClass *klass) FuSuperioDeviceClass *klass_superio_device = FU_SUPERIO_DEVICE_CLASS (klass); klass_device->attach = fu_superio_it89_device_attach; klass_device->detach = fu_superio_it89_device_detach; + klass_device->read_firmware = fu_superio_it89_device_read_firmware; klass_superio_device->setup = fu_superio_it89_device_setup; }