intel-spi: Allow downloading the firmware image from the eSPI controller

Add the IFD regions as child devices and set the region access on the child
devices. Also add read-only SPI descriptor as an HSI attribute and require
FLOCKDN on Intel hardware.

Use the hidden PCI 00:1f.5 device to set the SPIBAR automatically and generate
the quirk file automatically to support more hardware.
This commit is contained in:
Richard Hughes 2021-03-17 19:35:21 +00:00
parent b333e0045c
commit f3c64adb6c
18 changed files with 1696 additions and 31 deletions

View File

@ -393,6 +393,22 @@
</note>
</refsect3>
<refsect3 id="org.fwupd.hsi.Spi.Descriptor">
<title>Read-only SPI Descriptor</title>
<para>
The SPI descriptor must always be read only from all other regions.
Additionally on Intel architectures the FLOCKDN register must be set to
prevent configuration registers in the SPI BAR from being changed.
</para>
<itemizedlist>
<listitem>
<para>
For HSI-1 this should be read only from all regions <emphasis>v1.6.0</emphasis>
</para>
</listitem>
</itemizedlist>
</refsect3>
<refsect3 id="org.fwupd.hsi.Tpm.Version20">
<title>TPM 2.0 Present</title>
<para>

View File

@ -36,6 +36,7 @@ G_BEGIN_DECLS
#define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.Spi.Bioswe" /* Since: 1.5.0 */
#define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.Spi.Ble" /* Since: 1.5.0 */
#define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.Spi.SmmBwp" /* Since: 1.5.0 */
#define FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR "org.fwupd.hsi.Spi.Descriptor" /* Since: 1.6.0 */
#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE "org.fwupd.hsi.SuspendToIdle" /* Since: 1.5.0 */
#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM "org.fwupd.hsi.SuspendToRam" /* Since: 1.5.0 */
#define FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0 "org.fwupd.hsi.Tpm.ReconstructionPcr0" /* Since: 1.5.0 */

View File

@ -44,6 +44,42 @@ fu_ifd_region_to_string (FuIfdRegion region)
return NULL;
}
/**
* fu_ifd_region_to_name:
* @region: A #FuIfdRegion, e.g. %FU_IFD_REGION_BIOS
*
* Converts a #FuIfdRegion to a name the user might recognize.
*
* Return value: identifier string
*
* Since: 1.6.0
**/
const gchar *
fu_ifd_region_to_name (FuIfdRegion region)
{
if (region == FU_IFD_REGION_DESC)
return "IFD descriptor region";
if (region == FU_IFD_REGION_BIOS)
return "BIOS";
if (region == FU_IFD_REGION_ME)
return "Intel Management Engine";
if (region == FU_IFD_REGION_GBE)
return "Gigabit Ethernet";
if (region == FU_IFD_REGION_PLATFORM)
return "Platform firmware";
if (region == FU_IFD_REGION_DEVEXP)
return "Device Firmware";
if (region == FU_IFD_REGION_BIOS2)
return "BIOS Backup";
if (region == FU_IFD_REGION_EC)
return "Embedded Controller";
if (region == FU_IFD_REGION_IE)
return "Innovation Engine";
if (region == FU_IFD_REGION_10GBE)
return "10 Gigabit Ethernet";
return NULL;
}
/**
* fu_ifd_access_to_string:
* @access: A #FuIfdAccess, e.g. %FU_IFD_ACCESS_READ
@ -57,6 +93,8 @@ fu_ifd_region_to_string (FuIfdRegion region)
const gchar *
fu_ifd_access_to_string (FuIfdAccess access)
{
if (access == FU_IFD_ACCESS_NONE)
return "--";
if (access == FU_IFD_ACCESS_READ)
return "ro";
if (access == FU_IFD_ACCESS_WRITE)
@ -65,3 +103,35 @@ fu_ifd_access_to_string (FuIfdAccess access)
return "rw";
return NULL;
}
FuIfdAccess
fu_ifd_region_to_access (FuIfdRegion region, guint32 flash_master, gboolean is_skylake)
{
guint8 bit_r = 0;
guint8 bit_w = 0;
/* new layout */
if (is_skylake) {
bit_r = (flash_master >> (region + 8)) & 0b1;
bit_w = (flash_master >> (region + 20)) & 0b1;
return (bit_r ? FU_IFD_ACCESS_READ : FU_IFD_ACCESS_NONE) |
(bit_w ? FU_IFD_ACCESS_WRITE : FU_IFD_ACCESS_NONE);
}
/* old layout */
if (region == FU_IFD_REGION_DESC) {
bit_r = 16;
bit_w = 24;
} else if (region == FU_IFD_REGION_BIOS) {
bit_r = 17;
bit_w = 25;
} else if (region == FU_IFD_REGION_ME) {
bit_r = 18;
bit_w = 26;
} else if (region == FU_IFD_REGION_GBE) {
bit_r = 19;
bit_w = 27;
}
return ((flash_master >> bit_r) & 0b1 ? FU_IFD_ACCESS_READ : FU_IFD_ACCESS_NONE) |
((flash_master >> bit_w) & 0b1 ? FU_IFD_ACCESS_WRITE : FU_IFD_ACCESS_NONE);
}

View File

@ -28,5 +28,13 @@ typedef enum {
FU_IFD_ACCESS_WRITE = 1 << 1,
} FuIfdAccess;
#define FU_IFD_FREG_BASE(freg) (((freg) << 12) & 0x07FFF000)
#define FU_IFD_FREG_LIMIT(freg) ((((freg) >> 4) & 0x07FFF000) | 0x00000FFF)
const gchar *fu_ifd_region_to_string (FuIfdRegion region);
const gchar *fu_ifd_region_to_name (FuIfdRegion region);
const gchar *fu_ifd_access_to_string (FuIfdAccess access);
FuIfdAccess fu_ifd_region_to_access (FuIfdRegion region,
guint32 flash_master,
gboolean is_skylake);

View File

@ -0,0 +1,155 @@
/*
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include "fu-common.h"
#include "fu-ifd-device.h"
#include "fu-ifd-bios.h"
#include "fu-intel-spi-device.h"
typedef struct {
FuDevice parent_instance;
FuIfdRegion region;
guint32 offset;
FuIfdAccess access[FU_IFD_REGION_MAX];
} FuIfdDevicePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (FuIfdDevice, fu_ifd_device, FU_TYPE_DEVICE)
#define GET_PRIVATE(o) (fu_ifd_device_get_instance_private (o))
static void
fu_ifd_device_set_region (FuIfdDevice *self, FuIfdRegion region)
{
FuIfdDevicePrivate *priv = GET_PRIVATE (self);
const gchar *region_str = fu_ifd_region_to_string (region);
g_autofree gchar *instance_id = NULL;
g_autofree gchar *region_str_up = NULL;
priv->region = region;
fu_device_set_name (FU_DEVICE (self), fu_ifd_region_to_name (region));
fu_device_set_logical_id (FU_DEVICE (self), region_str);
region_str_up = g_ascii_strup (region_str, -1);
instance_id = g_strdup_printf ("IFD\\%s", region_str_up);
fu_device_add_instance_id (FU_DEVICE (self), instance_id);
}
static void
fu_ifd_device_set_freg (FuIfdDevice *self, guint32 freg)
{
FuIfdDevicePrivate *priv = GET_PRIVATE (self);
guint32 freg_base = FU_IFD_FREG_BASE (freg);
guint32 freg_limt = FU_IFD_FREG_LIMIT (freg);
guint32 freg_size = (freg_limt - freg_base) + 1;
priv->offset = freg_base;
fu_device_set_firmware_size (FU_DEVICE (self), freg_size);
}
void
fu_ifd_device_set_access (FuIfdDevice *self, FuIfdRegion region, FuIfdAccess access)
{
FuIfdDevicePrivate *priv = GET_PRIVATE (self);
priv->access[region] = access;
}
static gboolean
fu_ifd_device_open (FuDevice *device, GError **error)
{
return fu_device_open (fu_device_get_parent (device), error);
}
static gboolean
fu_ifd_device_close (FuDevice *device, GError **error)
{
return fu_device_close (fu_device_get_parent (device), error);
}
static void
fu_ifd_device_to_string (FuDevice *device, guint idt, GString *str)
{
FuIfdDevice *self = FU_IFD_DEVICE (device);
FuIfdDevicePrivate *priv = GET_PRIVATE (self);
fu_common_string_append_kv (str, idt, "Region",
fu_ifd_region_to_string (priv->region));
fu_common_string_append_kx (str, idt, "Offset", priv->offset);
for (guint i = 0; i < FU_IFD_REGION_MAX; i++) {
g_autofree gchar *title = NULL;
if (priv->access[i] == FU_IFD_ACCESS_NONE)
continue;
title = g_strdup_printf ("Access[%s]", fu_ifd_region_to_string (i));
fu_common_string_append_kv (str, idt, title,
fu_ifd_access_to_string (priv->access[i]));
}
}
static GBytes *
fu_ifd_device_dump_firmware (FuDevice *device, GError **error)
{
FuIfdDevice *self = FU_IFD_DEVICE (device);
FuIfdDevicePrivate *priv = GET_PRIVATE (self);
FuDevice *parent = fu_device_get_parent (device);
guint64 total_size = fu_device_get_firmware_size_max (device);
return fu_intel_spi_device_dump (FU_INTEL_SPI_DEVICE (parent),
device,
priv->offset,
total_size,
error);
}
static FuFirmware *
fu_ifd_device_read_firmware (FuDevice *device, GError **error)
{
FuIfdDevice *self = FU_IFD_DEVICE (device);
FuIfdDevicePrivate *priv = GET_PRIVATE (self);
g_autoptr(FuFirmware) firmware = fu_ifd_image_new ();
g_autoptr(GBytes) blob = NULL;
blob = fu_ifd_device_dump_firmware (device, error);
if (blob == NULL)
return NULL;
if (priv->region == FU_IFD_REGION_BIOS)
firmware = fu_ifd_bios_new ();
else
firmware = fu_ifd_image_new ();
if (!fu_firmware_parse (firmware, blob, FWUPD_INSTALL_FLAG_NONE, error))
return NULL;
return g_steal_pointer (&firmware);
}
static void
fu_ifd_device_init (FuIfdDevice *self)
{
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL);
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE);
fu_device_add_icon (FU_DEVICE (self), "computer");
}
static void
fu_ifd_device_class_init (FuIfdDeviceClass *klass)
{
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
klass_device->to_string = fu_ifd_device_to_string;
klass_device->dump_firmware = fu_ifd_device_dump_firmware;
klass_device->read_firmware = fu_ifd_device_read_firmware;
klass_device->open = fu_ifd_device_open;
klass_device->close = fu_ifd_device_close;
}
FuDevice *
fu_ifd_device_new (FuIfdRegion region, guint32 freg)
{
FuIfdDevice *self = FU_IFD_DEVICE (g_object_new (FU_TYPE_IFD_DEVICE, NULL));
fu_ifd_device_set_region (self, region);
fu_ifd_device_set_freg (self, freg);
return FU_DEVICE (self);
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include "fu-device.h"
#include "fu-ifd-common.h"
#define FU_TYPE_IFD_DEVICE (fu_ifd_device_get_type ())
G_DECLARE_DERIVABLE_TYPE (FuIfdDevice, fu_ifd_device, FU, IFD_DEVICE, FuDevice)
struct _FuIfdDeviceClass
{
FuDeviceClass parent_class;
};
FuDevice *fu_ifd_device_new (FuIfdRegion region,
guint32 freg);
void fu_ifd_device_set_access (FuIfdDevice *self,
FuIfdRegion region,
FuIfdAccess access);

View File

@ -204,8 +204,6 @@ fu_ifd_firmware_parse (FuFirmware *firmware,
guint32 freg_size = (freg_limt - freg_base) + 1;
g_autoptr(FuFirmware) img = NULL;
g_autoptr(GBytes) contents = NULL;
guint8 bit_r = 0;
guint8 bit_w = 0;
/* invalid */
if (freg_base > freg_limt)
@ -230,35 +228,10 @@ fu_ifd_firmware_parse (FuFirmware *firmware,
fu_firmware_add_image (firmware, img);
/* is writable by anything other than the region itself */
if (priv->is_skylake) {
for (FuIfdRegion r = 1; r <= 3; r++) {
bit_r = (priv->flash_master[r] >> (i + 8)) & 0b1;
bit_w = (priv->flash_master[r] >> (i + 20)) & 0b1;
fu_ifd_image_set_access (FU_IFD_IMAGE (img), r,
(bit_r ? FU_IFD_ACCESS_READ : FU_IFD_ACCESS_NONE) |
(bit_w ? FU_IFD_ACCESS_WRITE : FU_IFD_ACCESS_NONE));
}
} else {
if (i == FU_IFD_REGION_DESC) {
bit_r = 16;
bit_w = 24;
} else if (i == FU_IFD_REGION_BIOS) {
bit_r = 17;
bit_w = 25;
} else if (i == FU_IFD_REGION_ME) {
bit_r = 18;
bit_w = 26;
} else if (i == FU_IFD_REGION_GBE) {
bit_r = 19;
bit_w = 27;
}
for (FuIfdRegion r = 1; r <= 3 && bit_r != 0; r++) {
fu_ifd_image_set_access (FU_IFD_IMAGE (img), r,
((priv->flash_master[r] >> bit_r) & 0b1 ?
FU_IFD_ACCESS_READ : FU_IFD_ACCESS_NONE) |
((priv->flash_master[r] >> bit_w) & 0b1 ?
FU_IFD_ACCESS_WRITE : FU_IFD_ACCESS_NONE));
}
for (FuIfdRegion r = 1; r <= 3; r++) {
FuIfdAccess acc;
acc = fu_ifd_region_to_access (i, priv->flash_master[r], priv->is_skylake);
fu_ifd_image_set_access (FU_IFD_IMAGE (img), r, acc);
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: GPL-2+
*/
#include "config.h"
#include "fu-intel-spi-common.h"
FuIntelSpiKind
fu_intel_spi_kind_from_string (const gchar *kind)
{
if (g_strcmp0 (kind, "ich9") == 0)
return FU_INTEL_SPI_KIND_ICH9;
if (g_strcmp0 (kind, "pch100") == 0)
return FU_INTEL_SPI_KIND_PCH100;
if (g_strcmp0 (kind, "apl") == 0)
return FU_INTEL_SPI_KIND_APL;
if (g_strcmp0 (kind, "c620") == 0)
return FU_INTEL_SPI_KIND_C620;
if (g_strcmp0 (kind, "ich0") == 0)
return FU_INTEL_SPI_KIND_ICH0;
if (g_strcmp0 (kind, "ich2345") == 0)
return FU_INTEL_SPI_KIND_ICH2345;
if (g_strcmp0 (kind, "ich6") == 0)
return FU_INTEL_SPI_KIND_ICH6;
if (g_strcmp0 (kind, "pch300") == 0)
return FU_INTEL_SPI_KIND_PCH300;
if (g_strcmp0 (kind, "pch400") == 0)
return FU_INTEL_SPI_KIND_PCH400;
if (g_strcmp0 (kind, "poulsbo") == 0)
return FU_INTEL_SPI_KIND_POULSBO;
return FU_INTEL_SPI_KIND_UNKNOWN;
}
const gchar *
fu_intel_spi_kind_to_string (FuIntelSpiKind kind)
{
if (kind == FU_INTEL_SPI_KIND_ICH9)
return "ich9";
if (kind == FU_INTEL_SPI_KIND_PCH100)
return "pch100";
if (kind == FU_INTEL_SPI_KIND_APL)
return "apl";
if (kind == FU_INTEL_SPI_KIND_C620)
return "c620";
if (kind == FU_INTEL_SPI_KIND_ICH0)
return "ich0";
if (kind == FU_INTEL_SPI_KIND_ICH2345)
return "ich2345";
if (kind == FU_INTEL_SPI_KIND_ICH6)
return "ich6";
if (kind == FU_INTEL_SPI_KIND_PCH300)
return "pch300";
if (kind == FU_INTEL_SPI_KIND_PCH400)
return "pch400";
if (kind == FU_INTEL_SPI_KIND_POULSBO)
return "poulsbo";
return NULL;
}
guint16
fu_mmio_read16 (gconstpointer addr, goffset offset)
{
addr = (guint8 *) addr + offset;
return *(volatile const guint16 *) addr;
}
guint32
fu_mmio_read32 (gconstpointer addr, goffset offset)
{
addr = (guint8 *) addr + offset;
return *(volatile const guint32 *) addr;
}
void
fu_mmio_write16 (gpointer addr, goffset offset, guint16 val)
{
addr = (guint8 *) addr + offset;
*(volatile guint16 *) addr = val;
}
void
fu_mmio_write32 (gpointer addr, goffset offset, guint32 val)
{
addr = (guint8 *) addr + offset;
*(volatile guint32 *) addr = val;
}
guint32
fu_mmio_read32_le (gconstpointer addr, goffset offset)
{
return GUINT32_FROM_LE (fu_mmio_read32 (addr, offset));
}
void
fu_mmio_write32_le (gpointer addr, goffset offset, guint32 val)
{
fu_mmio_write32 (addr, offset, GUINT32_TO_LE (val));
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include <glib.h>
#define ICH9_REG_BFPR 0x00
#define ICH9_REG_HSFS 0x04
#define ICH9_REG_HSFC 0x06
#define ICH9_REG_FADDR 0x08
#define ICH9_REG_RESRVD 0x0C
#define ICH9_REG_FDATA0 0x10
#define ICH9_REG_FDATAN 0x14
#define ICH9_REG_FRAP 0x50
#define ICH9_REG_FREG0 0x54
#define ICH9_REG_PR0 0x74
#define ICH9_REG_FDOC 0xB0
#define ICH9_REG_FDOD 0xB4
#define PCH100_REG_FDOC 0xB4
#define PCH100_REG_FDOD 0xB8
#define PCH100_REG_FPR0 0x84
#define PCH100_REG_GPR0 0x98
#define PCH100_FADDR_FLA 0x07ffffff
#define PCH100_HSFC_FCYCLE (0xf << 1)
#define FDOC_FDSI (0x3F << 2)
#define FDOC_FDSS (0x03 << 12)
#define HSFS_FDONE (0x01 << 0)
#define HSFS_FCERR (0x01 << 1)
#define HSFS_AEL (0x01 << 2)
#define HSFS_BERASE (0x03 << 3)
#define HSFS_SCIP (0x01 << 5)
#define HSFS_FDOPSS (0x01 << 13)
#define HSFS_FDV (0x01 << 14)
#define HSFS_FLOCKDN (0x01 << 15)
#define HSFC_FGO (0x01 << 0)
#define HSFC_FCYCLE (0x03 << 1)
#define HSFC_FDBC (0x3f << 8)
#define HSFC_SME (0x01 << 15)
typedef enum {
FU_INTEL_SPI_KIND_UNKNOWN,
FU_INTEL_SPI_KIND_APL,
FU_INTEL_SPI_KIND_C620,
FU_INTEL_SPI_KIND_ICH0,
FU_INTEL_SPI_KIND_ICH2345,
FU_INTEL_SPI_KIND_ICH6,
FU_INTEL_SPI_KIND_ICH9,
FU_INTEL_SPI_KIND_PCH100,
FU_INTEL_SPI_KIND_PCH300,
FU_INTEL_SPI_KIND_PCH400,
FU_INTEL_SPI_KIND_POULSBO,
FU_INTEL_SPI_KIND_LAST
} FuIntelSpiKind;
FuIntelSpiKind fu_intel_spi_kind_from_string (const gchar *kind);
const gchar *fu_intel_spi_kind_to_string (FuIntelSpiKind kind);
guint16 fu_mmio_read16 (gconstpointer addr,
goffset offset);
void fu_mmio_write16 (gpointer addr,
goffset offset,
guint16 val);
guint32 fu_mmio_read32 (gconstpointer addr,
goffset offset);
void fu_mmio_write32 (gpointer addr,
goffset offset,
guint32 val);
guint32 fu_mmio_read32_le (gconstpointer addr,
goffset offset);
void fu_mmio_write32_le (gpointer addr,
goffset offset,
guint32 val);

View File

@ -0,0 +1,506 @@
/*
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: GPL-2+
*/
#include "config.h"
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <gio/gunixinputstream.h>
#include "fu-device-locker.h"
#include "fu-plugin-vfuncs.h"
#include "fu-pci-device.h"
#include "fu-intel-spi-common.h"
#include "fu-intel-spi-device.h"
#include "fu-ifd-common.h"
#include "fu-ifd-device.h"
#include "fu-ifd-firmware.h"
struct _FuIntelSpiDevice {
FuDevice parent_instance;
FuIntelSpiKind kind;
gchar *spibar_proxy;
guint32 phys_spibar;
gpointer spibar;
guint16 hsfs;
guint16 frap;
guint32 freg[4];
guint32 flvalsig;
guint32 descriptor_map0;
guint32 descriptor_map1;
guint32 descriptor_map2;
guint32 components_rcd;
guint32 illegal_jedec;
guint32 flpb;
guint32 flash_master[4];
guint32 protected_range[4];
};
#define FU_INTEL_SPI_PHYS_SPIBAR_SIZE 0x10000 /* bytes */
#define FU_INTEL_SPI_READ_TIMEOUT 10 /* ms */
#define PCI_BASE_ADDRESS_0 0x0010
G_DEFINE_TYPE (FuIntelSpiDevice, fu_intel_spi_device, FU_TYPE_DEVICE)
static void
fu_intel_spi_device_to_string (FuDevice *device, guint idt, GString *str)
{
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE (device);
fu_common_string_append_kv (str, idt, "Kind",
fu_intel_spi_kind_to_string (self->kind));
fu_common_string_append_kx (str, idt, "SPIBAR", self->phys_spibar);
fu_common_string_append_kx (str, idt, "HSFS", self->hsfs);
fu_common_string_append_kx (str, idt, "FRAP", self->frap);
for (guint i = 0; i < 4; i++) {
g_autofree gchar *title = g_strdup_printf ("FREG%u", i);
fu_common_string_append_kx (str, idt, title, self->freg[i]);
}
for (guint i = 0; i < 4; i++) {
g_autofree gchar *title = g_strdup_printf ("FLMSTR%u", i);
fu_common_string_append_kx (str, idt, title, self->flash_master[i]);
}
fu_common_string_append_kx (str, idt, "FLVALSIG", self->flvalsig);
fu_common_string_append_kx (str, idt, "FLMAP0", self->descriptor_map0);
fu_common_string_append_kx (str, idt, "FLMAP1", self->descriptor_map1);
fu_common_string_append_kx (str, idt, "FLMAP2", self->descriptor_map2);
fu_common_string_append_kx (str, idt, "FLCOMP", self->components_rcd);
fu_common_string_append_kx (str, idt, "FLILL", self->illegal_jedec);
fu_common_string_append_kx (str, idt, "FLPB", self->flpb);
/* PRx */
for (guint i = 0; i < 4; i++) {
guint32 limit = 0;
guint32 base = 0;
FuIfdAccess access = FU_IFD_ACCESS_NONE;
g_autofree gchar *title = NULL;
g_autofree gchar *tmp = NULL;
if (self->protected_range[i] == 0x0)
continue;
if ((self->protected_range[i] >> 31) & 0b1)
access |= FU_IFD_ACCESS_WRITE;
if ((self->protected_range[i] >> 15) & 0b1)
access |= FU_IFD_ACCESS_READ;
if (access != FU_IFD_ACCESS_NONE) {
base = ((self->protected_range[i] >> 0) & 0x1FFF) << 12;
limit = (((self->protected_range[i] >> 16) & 0x1FFF) << 12) | 0xFFFF;
}
title = g_strdup_printf ("PR%u", i);
tmp = g_strdup_printf ("blocked %s from 0x%x to 0x%x [0x%x]",
fu_ifd_access_to_string (access),
base, limit,
self->protected_range[i]);
fu_common_string_append_kv (str, idt, title, tmp);
}
}
static gboolean
fu_intel_spi_device_open (FuDevice *device, GError **error)
{
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE (device);
int fd;
g_autoptr(GInputStream) istr = NULL;
/* this will fail if the kernel is locked down */
fd = open ("/dev/mem", O_SYNC | O_RDWR);
if (fd == -1) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"failed to open /dev/mem: %s",
strerror (errno));
return FALSE;
}
istr = g_unix_input_stream_new (fd, TRUE);
if (istr == NULL) {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"failed to create input stream");
return FALSE;
}
self->spibar = mmap (NULL, FU_INTEL_SPI_PHYS_SPIBAR_SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED, fd,
self->phys_spibar);
if (self->spibar == MAP_FAILED) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"failed to open mmap SPIBAR: %s",
strerror (errno));
return FALSE;
}
/* success */
return TRUE;
}
static gboolean
fu_intel_spi_device_close (FuDevice *device, GError **error)
{
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE (device);
/* close */
if (self->spibar != NULL) {
if (munmap (self->spibar, FU_INTEL_SPI_PHYS_SPIBAR_SIZE) == -1) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"failed to unmap spibar: %s",
strerror (errno));
return FALSE;
}
self->spibar = NULL;
}
/* success */
return TRUE;
}
static guint32
fu_intel_spi_device_read_reg (FuIntelSpiDevice *self, guint8 section, guint16 offset)
{
guint32 control = 0;
control |= (((guint32) section) << 12) & FDOC_FDSS;
control |= (((guint32) offset) << 2) & FDOC_FDSI;
fu_mmio_write32_le (self->spibar, PCH100_REG_FDOC, control);
return fu_mmio_read32_le (self->spibar, PCH100_REG_FDOD);
}
static void
fu_intel_spi_device_add_security_attrs (FuDevice *device, FuSecurityAttrs *attrs)
{
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE (device);
FuIfdAccess access_global = FU_IFD_ACCESS_NONE;
g_autoptr(FwupdSecurityAttr) attr = NULL;
/* create attr */
attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR);
fwupd_security_attr_set_plugin (attr, fu_device_get_plugin (FU_DEVICE (self)));
fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL);
fu_security_attrs_append (attrs, attr);
/* check for read access from other regions */
for (guint j = FU_IFD_REGION_BIOS; j < 4; j++) {
FuIfdAccess access;
access = fu_ifd_region_to_access (FU_IFD_REGION_DESC,
self->flash_master[j-1], TRUE);
fwupd_security_attr_add_metadata (attr,
fu_ifd_region_to_string (j),
fu_ifd_access_to_string (access));
access_global |= access;
}
/* any region can write to the flash descriptor */
if (access_global & FU_IFD_ACCESS_WRITE) {
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
return;
}
/* FLOCKDN is unset */
if ((self->hsfs >> 15 & 0b1) == 0) {
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED);
return;
}
/* success */
fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED);
}
static gboolean
fu_intel_spi_device_probe (FuDevice *device, GError **error)
{
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE (device);
/* verify this was set in the quirk file */
if (self->kind == FU_INTEL_SPI_KIND_UNKNOWN) {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"IntelSpiKind not set");
return FALSE;
}
/* use a hidden PCI device to get the RCBA */
if (self->spibar_proxy != NULL) {
g_autoptr(FuDevice) pcidev = NULL;
g_autoptr(FuDeviceLocker) locker = NULL;
/* get SPIBAR from a hidden (VID set to 0xFFFF) PCI device */
pcidev = fu_pci_device_new (self->spibar_proxy, error);
if (pcidev == NULL)
return FALSE;
locker = fu_device_locker_new (pcidev, error);
if (locker == NULL)
return FALSE;
self->phys_spibar = fu_pci_device_read_config (FU_PCI_DEVICE (pcidev),
PCI_BASE_ADDRESS_0);
if (self->phys_spibar == 0 ||
self->phys_spibar == G_MAXUINT32) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"SPIBAR not valid: 0x%x",
self->phys_spibar);
return FALSE;
}
}
/* specified explicitly as a physical address */
if (self->phys_spibar == 0) {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"IntelSpiBar not set");
return FALSE;
}
/* success */
return TRUE;
}
static gboolean
fu_intel_spi_device_setup (FuDevice *device, GError **error)
{
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE (device);
guint64 total_size = 0;
guint8 comp1_density;
guint8 comp2_density;
guint16 reg_pr0 = fu_device_has_custom_flag (device, "ICH") ? ICH9_REG_PR0 : PCH100_REG_FPR0;
/* dump everything */
if (g_getenv ("FWUPD_INTEL_SPI_VERBOSE") != NULL) {
for (guint i = 0; i < 0xff; i += 4) {
guint32 tmp = fu_mmio_read32 (self->spibar, i);
g_print ("SPIBAR[0x%02x] = 0x%x\n", i, tmp);
}
}
/* read from descriptor */
self->hsfs = fu_mmio_read16 (self->spibar, ICH9_REG_HSFS);
self->frap = fu_mmio_read16 (self->spibar, ICH9_REG_FRAP);
for (guint i = FU_IFD_REGION_DESC; i < 4; i++)
self->freg[i] = fu_mmio_read32 (self->spibar, ICH9_REG_FREG0 + i * 4);
self->flvalsig = fu_intel_spi_device_read_reg (self, 0, 0);
self->descriptor_map0 = fu_intel_spi_device_read_reg (self, 0, 1);
self->descriptor_map1 = fu_intel_spi_device_read_reg (self, 0, 2);
self->descriptor_map2 = fu_intel_spi_device_read_reg (self, 0, 3);
self->components_rcd = fu_intel_spi_device_read_reg (self, 1, 0);
self->illegal_jedec = fu_intel_spi_device_read_reg (self, 1, 1);
self->flpb = fu_intel_spi_device_read_reg (self, 1, 2);
for (guint i = 0; i < 4; i++)
self->flash_master[i] = fu_intel_spi_device_read_reg (self, 3, i);
for (guint i = 0; i < 4; i++) {
self->protected_range[i] = fu_mmio_read32 (self->spibar,
reg_pr0 + i * sizeof(guint32));
}
/* set size */
comp1_density = (self->components_rcd & 0x0f) >> 0;
if (comp1_density != 0xf)
total_size += 1 << (19 + comp1_density);
comp2_density = (self->components_rcd & 0xf0) >> 4;
if (comp2_density != 0xf)
total_size += 1 << (19 + comp2_density);
fu_device_set_firmware_size (device, total_size);
/* add children */
for (guint i = FU_IFD_REGION_BIOS; i < 4; i++) {
g_autoptr(FuDevice) child = NULL;
if (self->freg[i] == 0x0)
continue;
child = fu_ifd_device_new (i, self->freg[i]);
for (guint j = 1; j < 4; j++) {
FuIfdAccess access;
access = fu_ifd_region_to_access (i, self->flash_master[j-1], TRUE);
fu_ifd_device_set_access (FU_IFD_DEVICE (child), j, access);
}
fu_device_add_child (device, child);
}
return TRUE;
}
static gboolean
fu_intel_spi_device_wait (FuIntelSpiDevice *self, guint timeout_ms, GError **error)
{
g_usleep (1);
for (guint i = 0; i < timeout_ms * 100; i++) {
guint16 hsfs = fu_mmio_read16 (self->spibar, ICH9_REG_HSFS);
if (hsfs & HSFS_FDONE)
return TRUE;
if (hsfs & HSFS_FCERR) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"HSFS transaction error");
return FALSE;
}
g_usleep (10);
}
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_TIMED_OUT,
"HSFS timed out");
return FALSE;
}
static void
fu_intel_spi_device_set_addr (FuIntelSpiDevice *self, guint32 addr)
{
guint32 addr_old = fu_mmio_read32 (self->spibar, ICH9_REG_FADDR) & ~PCH100_FADDR_FLA;
fu_mmio_write32 (self->spibar, ICH9_REG_FADDR, (addr & PCH100_FADDR_FLA) | addr_old);
}
GBytes *
fu_intel_spi_device_dump (FuIntelSpiDevice *self,
FuDevice *device,
guint32 offset,
guint32 length,
GError **error)
{
guint8 block_len = 0x40;
g_autoptr(GByteArray) buf = g_byte_array_sized_new (length);
/* set FDONE, FCERR, AEL */
fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ);
fu_mmio_write16 (self->spibar, ICH9_REG_HSFS,
fu_mmio_read16 (self->spibar, ICH9_REG_HSFS));
for (guint32 addr = offset; addr < offset + length; addr += block_len) {
guint16 hsfc;
guint32 buftmp32 = 0;
/* set up read */
fu_intel_spi_device_set_addr (self, addr);
hsfc = fu_mmio_read16 (self->spibar, ICH9_REG_HSFC);
hsfc &= ~PCH100_HSFC_FCYCLE;
hsfc &= ~HSFC_FDBC;
/* set byte count */
hsfc |= ((block_len - 1) << 8) & HSFC_FDBC;
hsfc |= HSFC_FGO;
fu_mmio_write16 (self->spibar, ICH9_REG_HSFC, hsfc);
if (!fu_intel_spi_device_wait (self, FU_INTEL_SPI_READ_TIMEOUT, error)) {
g_prefix_error (error, "failed @0x%x: ", addr);
return NULL;
}
/* copy out data */
for (guint i = 0; i < block_len; i++) {
if (i % 4 == 0)
buftmp32 = fu_mmio_read32 (self->spibar, ICH9_REG_FDATA0 + i);
fu_byte_array_append_uint8 (buf, buftmp32 >> ((i % 4) * 8));
}
/* progress */
fu_device_set_progress_full (device, addr - offset + block_len, length);
}
/* success */
return g_byte_array_free_to_bytes (g_steal_pointer (&buf));
}
static GBytes *
fu_intel_spi_device_dump_firmware (FuDevice *device, GError **error)
{
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE (device);
guint64 total_size = fu_device_get_firmware_size_max (device);
return fu_intel_spi_device_dump (self, device,
0x0, total_size,
error);
}
static FuFirmware *
fu_intel_spi_device_read_firmware (FuDevice *device, GError **error)
{
g_autoptr(FuFirmware) firmware = fu_ifd_firmware_new ();
g_autoptr(GBytes) blob = NULL;
blob = fu_intel_spi_device_dump_firmware (device, error);
if (blob == NULL)
return NULL;
if (!fu_firmware_parse (firmware, blob, FWUPD_INSTALL_FLAG_NONE, error))
return NULL;
return g_steal_pointer (&firmware);
}
static gboolean
fu_intel_spi_device_set_quirk_kv (FuDevice *device,
const gchar *key,
const gchar *value,
GError **error)
{
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE (device);
if (g_strcmp0 (key, "IntelSpiBar") == 0) {
guint64 tmp = fu_common_strtoull (value);
self->phys_spibar = tmp;
return TRUE;
}
if (g_strcmp0 (key, "IntelSpiKind") == 0) {
g_autofree gchar *instance_id = NULL;
g_autofree gchar *kind_up = NULL;
/* validate */
self->kind = fu_intel_spi_kind_from_string (value);
if (self->kind == FU_INTEL_SPI_KIND_UNKNOWN) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"%s not supported",
value);
return FALSE;
}
/* get things like SPIBAR */
kind_up = g_ascii_strup (value, -1);
instance_id = g_strdup_printf ("INTEL_SPI_CHIPSET\\%s", kind_up);
fu_device_add_instance_id (device, instance_id);
return TRUE;
}
if (g_strcmp0 (key, "IntelSpiBarProxy") == 0) {
self->spibar_proxy = g_strdup (value);
return TRUE;
}
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"no supported");
return FALSE;
}
static void
fu_intel_spi_device_init (FuIntelSpiDevice *self)
{
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL);
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE);
fu_device_add_icon (FU_DEVICE (self), "computer");
fu_device_set_physical_id (FU_DEVICE (self), "intel_spi");
}
static void
fu_intel_spi_device_class_init (FuIntelSpiDeviceClass *klass)
{
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
klass_device->to_string = fu_intel_spi_device_to_string;
klass_device->probe = fu_intel_spi_device_probe;
klass_device->setup = fu_intel_spi_device_setup;
klass_device->dump_firmware = fu_intel_spi_device_dump_firmware;
klass_device->read_firmware = fu_intel_spi_device_read_firmware;
klass_device->open = fu_intel_spi_device_open;
klass_device->close = fu_intel_spi_device_close;
klass_device->set_quirk_kv = fu_intel_spi_device_set_quirk_kv;
klass_device->add_security_attrs = fu_intel_spi_device_add_security_attrs;
}

View File

@ -0,0 +1,18 @@
/*
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include "fu-plugin.h"
#define FU_TYPE_INTEL_SPI_DEVICE (fu_intel_spi_device_get_type ())
G_DECLARE_FINAL_TYPE (FuIntelSpiDevice, fu_intel_spi_device, FU, INTEL_SPI_DEVICE, FuDevice)
GBytes *fu_intel_spi_device_dump (FuIntelSpiDevice *self,
FuDevice *device,
guint32 offset,
guint32 length,
GError **error);

View File

@ -0,0 +1,175 @@
/*
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <errno.h>
#include <sys/io.h>
#include "fu-common.h"
#include "fu-pci-device.h"
typedef struct {
FuDevice parent_instance;
guint32 bus;
guint32 dev;
guint32 fun;
} FuPciDevicePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (FuPciDevice, fu_pci_device, FU_TYPE_DEVICE)
#define PCI_CONFIG_ADDRESS 0x0CF8
#define PCI_CONFIG_DATA 0x0CFC
#define GET_PRIVATE(o) (fu_pci_device_get_instance_private (o))
guint32
fu_pci_device_read_config (FuPciDevice *self, guint32 addr)
{
FuPciDevicePrivate *priv = GET_PRIVATE (self);
guint32 val = 0x80000000;
/* we have to do this horrible port access as the PCI device is not
* visible to even the kernel as the vendor ID is set as 0xFFFF */
val |= priv->bus << 16;
val |= priv->dev << 11;
val |= priv->fun << 8;
val |= addr;
/* we do this multiple times until we get the same result for every
* request as the port is shared between the kernel and all processes */
for (guint cnt = 0; cnt < 0xff; cnt++) {
guint32 results[0x20] = { 0x0 };
gboolean consistent = TRUE;
/* fill up array */
for (guint i = 0; i < G_N_ELEMENTS(results); i++) {
outl (val, PCI_CONFIG_ADDRESS);
results[i] = inl (PCI_CONFIG_DATA);
}
/* check they are all the same */
for (guint i = 0; i < G_N_ELEMENTS(results); i++) {
if (results[0] != results[i]) {
consistent = FALSE;
break;
}
}
/* success */
if (consistent)
return results[0];
}
/* failed */
return G_MAXUINT32;
}
static gboolean
fu_pci_device_open (FuDevice *device, GError **error)
{
/* this will fail if userspace is locked down */
if (ioperm (PCI_CONFIG_ADDRESS, 64, 1) < 0) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"failed to open port: %s",
strerror (errno));
return FALSE;
}
/* success */
return TRUE;
}
static gboolean
fu_pci_device_close (FuDevice *device, GError **error)
{
/* this might fail if userspace is locked down */
if (ioperm (PCI_CONFIG_ADDRESS, 64, 0) < 0) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"failed to open port: %s",
strerror (errno));
return FALSE;
}
/* success */
return TRUE;
}
static void
fu_pci_device_to_string (FuDevice *device, guint idt, GString *str)
{
FuPciDevice *self = FU_PCI_DEVICE (device);
FuPciDevicePrivate *priv = GET_PRIVATE (self);
fu_common_string_append_kx (str, idt, "Bus", priv->bus);
fu_common_string_append_kx (str, idt, "Dev", priv->dev);
fu_common_string_append_kx (str, idt, "Fun", priv->fun);
}
static gboolean
fu_pci_device_parse_bdf (FuPciDevice *self, const gchar *bdf, GError **error)
{
FuPciDevicePrivate *priv = GET_PRIVATE (self);
guint64 bus_tmp;
guint64 dev_tmp;
guint64 fun_tmp;
g_auto(GStrv) split = g_strsplit_set (bdf, ":.", 0);
/* parse the BDF */
if (g_strv_length (split) != 3) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"%s invalid, expected '00:1f.5'",
bdf);
return FALSE;
}
bus_tmp = g_ascii_strtoull (split[0], NULL, 16);
dev_tmp = g_ascii_strtoull (split[1], NULL, 16);
fun_tmp = g_ascii_strtoull (split[2], NULL, 16);
if (bus_tmp > 0xff || dev_tmp > 0x1f || fun_tmp > 0x7) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"%s invalid, expected '00:1f.5'",
bdf);
return FALSE;
}
/* success */
priv->bus = bus_tmp;
priv->dev = dev_tmp;
priv->fun = fun_tmp;
return TRUE;
}
static void
fu_pci_device_init (FuPciDevice *self)
{
fu_device_set_physical_id (FU_DEVICE (self), "PCI");
}
static void
fu_pci_device_class_init (FuPciDeviceClass *klass)
{
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
klass_device->to_string = fu_pci_device_to_string;
klass_device->open = fu_pci_device_open;
klass_device->close = fu_pci_device_close;
}
FuDevice *
fu_pci_device_new (const gchar *bdf, GError **error)
{
g_autoptr(FuPciDevice) self = FU_PCI_DEVICE (g_object_new (FU_TYPE_PCI_DEVICE, NULL));
if (!fu_pci_device_parse_bdf (self, bdf, error))
return NULL;
return FU_DEVICE (g_steal_pointer (&self));
}

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include "fu-device.h"
#define FU_TYPE_PCI_DEVICE (fu_pci_device_get_type ())
G_DECLARE_DERIVABLE_TYPE (FuPciDevice, fu_pci_device, FU, PCI_DEVICE, FuDevice)
struct _FuPciDeviceClass
{
FuDeviceClass parent_class;
};
FuDevice *fu_pci_device_new (const gchar *bdf,
GError **error);
guint32 fu_pci_device_read_config (FuPciDevice *self,
guint32 addr);

View File

@ -8,6 +8,8 @@
#include "fu-plugin-vfuncs.h"
#include "fu-intel-spi-device.h"
#include "fu-ifd-firmware.h"
#include "fu-ifd-bios.h"
@ -19,6 +21,7 @@
void
fu_plugin_init (FuPlugin *plugin)
{
FuContext *ctx = fu_plugin_get_context (plugin);
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_EFI_FIRMWARE_FILE);
fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_EFI_FIRMWARE_FILESYSTEM);
@ -26,4 +29,23 @@ fu_plugin_init (FuPlugin *plugin)
fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_EFI_FIRMWARE_VOLUME);
fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_IFD_BIOS);
fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_IFD_FIRMWARE);
fu_context_add_udev_subsystem (ctx, "pci");
fu_context_add_quirk_key (ctx, "IntelSpiKind");
fu_context_add_quirk_key (ctx, "IntelSpiBar");
fu_context_add_quirk_key (ctx, "IntelSpiBarProxy");
fu_context_add_quirk_key (ctx, "IntelSpiBiosCntl");
fu_plugin_set_device_gtype (plugin, FU_TYPE_INTEL_SPI_DEVICE);
}
gboolean
fu_plugin_startup (FuPlugin *plugin, GError **error)
{
if (fu_common_kernel_locked_down ()) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"not supported when kernel locked down");
return FALSE;
}
return TRUE;
}

View File

@ -0,0 +1,76 @@
#!/usr/bin/python3
# pylint: disable=invalid-name,missing-docstring
#
# Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
#
# SPDX-License-Identifier: LGPL-2.1+
import sys
class Chipset:
def __init__(self, spibar=None, bios_cntl=0x0, spibar_proxy=None, flags=None):
self.bios_cntl = bios_cntl
self.spibar_proxy = spibar_proxy
self.spibar = spibar
self.flags = flags
if __name__ == "__main__":
if len(sys.argv) != 2:
print("required: /path/to/chipset_enable.c")
sys.exit(1)
chipsets = {
"apl": Chipset(flags="PCH", bios_cntl=0xDC, spibar_proxy="00:0d.2"),
"c620": Chipset(flags="PCH", bios_cntl=0xDC, spibar_proxy="00:1f.5"),
"ich0": Chipset(flags="ICH", bios_cntl=0x4E),
"ich2345": Chipset(flags="ICH", bios_cntl=0x4E),
"ich6": Chipset(flags="ICH", bios_cntl=0xDC),
"pch100": Chipset(flags="PCH", bios_cntl=0xDC, spibar_proxy="00:1f.5"),
"pch300": Chipset(flags="PCH", bios_cntl=0xDC, spibar_proxy="00:1f.5"),
"pch400": Chipset(flags="PCH", bios_cntl=0xDC, spibar_proxy="00:1f.5"),
"poulsbo": Chipset(flags="ICH", bios_cntl=0xD8),
}
devices = {"PCI\VEN_8086&DEV_A0A4": "pch100"}
with open("intel-spi.quirk", "w") as out_f:
with open(sys.argv[1], "r") as in_f:
lines = in_f.read().split("\n")
for line in lines:
if line.find("0x8086") == -1:
continue
if line.find("Sample") != -1:
continue
for char in ["}", "{", '"', " ", "\t"]:
line = line.replace(char, "")
ven, dev, _, _, _, _, kind, _ = line.split(",")
if kind.startswith("enable_flash_"):
kind = kind[13:]
if kind not in chipsets:
print("ignoring {}...".format(kind))
continue
devices["PCI\VEN_{}&DEV_{}".format(ven[2:], dev[2:].upper())] = kind
for device in devices:
kind = devices[device]
out_f.write("[{}]\n".format(device))
out_f.write("Plugin = intel_spi\n")
out_f.write("IntelSpiKind = {}\n\n".format(kind))
for kind in sorted(chipsets):
cs = chipsets[kind]
out_f.write("\n[INTEL_SPI_CHIPSET\\{}]\n".format(kind.upper()))
if cs.spibar:
out_f.write("IntelSpiBar = 0x{:x}\n".format(cs.spibar))
if cs.spibar_proxy:
out_f.write("IntelSpiBarProxy = {}\n".format(cs.spibar_proxy))
if cs.bios_cntl:
out_f.write("IntelSpiBiosCntl = 0x{:X}\n".format(cs.bios_cntl))
if cs.flags:
out_f.write("Flags = {}\n".format(cs.flags))

View File

@ -0,0 +1,401 @@
[PCI\VEN_8086&DEV_A0A4]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_2410]
Plugin = intel_spi
IntelSpiKind = ich0
[PCI\VEN_8086&DEV_2420]
Plugin = intel_spi
IntelSpiKind = ich0
[PCI\VEN_8086&DEV_2440]
Plugin = intel_spi
IntelSpiKind = ich2345
[PCI\VEN_8086&DEV_244C]
Plugin = intel_spi
IntelSpiKind = ich2345
[PCI\VEN_8086&DEV_2450]
Plugin = intel_spi
IntelSpiKind = ich2345
[PCI\VEN_8086&DEV_2480]
Plugin = intel_spi
IntelSpiKind = ich2345
[PCI\VEN_8086&DEV_248C]
Plugin = intel_spi
IntelSpiKind = ich2345
[PCI\VEN_8086&DEV_24C0]
Plugin = intel_spi
IntelSpiKind = ich2345
[PCI\VEN_8086&DEV_24CC]
Plugin = intel_spi
IntelSpiKind = ich2345
[PCI\VEN_8086&DEV_24D0]
Plugin = intel_spi
IntelSpiKind = ich2345
[PCI\VEN_8086&DEV_25A1]
Plugin = intel_spi
IntelSpiKind = ich2345
[PCI\VEN_8086&DEV_2640]
Plugin = intel_spi
IntelSpiKind = ich6
[PCI\VEN_8086&DEV_2641]
Plugin = intel_spi
IntelSpiKind = ich6
[PCI\VEN_8086&DEV_2642]
Plugin = intel_spi
IntelSpiKind = ich6
[PCI\VEN_8086&DEV_2670]
Plugin = intel_spi
IntelSpiKind = ich6
[PCI\VEN_8086&DEV_8119]
Plugin = intel_spi
IntelSpiKind = poulsbo
[PCI\VEN_8086&DEV_9D43]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_9D46]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_9D48]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_9D4B]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_9D4E]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_9D50]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_9D53]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_9D56]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_9D58]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_9D84]
Plugin = intel_spi
IntelSpiKind = pch300
[PCI\VEN_8086&DEV_0284]
Plugin = intel_spi
IntelSpiKind = pch400
[PCI\VEN_8086&DEV_0285]
Plugin = intel_spi
IntelSpiKind = pch400
[PCI\VEN_8086&DEV_A143]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A144]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A145]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A146]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A147]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A148]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A149]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A14A]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A14D]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A14E]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A150]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A151]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A152]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A153]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A154]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A155]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A1A4]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1C0]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1C1]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1C2]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1C3]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1C4]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1C5]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1C6]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1C7]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1C8]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1C9]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1CA]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1CB]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1CC]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A1CD]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A240]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A241]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A242]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A243]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A244]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A245]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A246]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A247]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A248]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A249]
Plugin = intel_spi
IntelSpiKind = c620
[PCI\VEN_8086&DEV_A2C4]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A2C5]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A2C6]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A2C7]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A2C8]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A2C9]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_A2D2]
Plugin = intel_spi
IntelSpiKind = pch100
[PCI\VEN_8086&DEV_5AE8]
Plugin = intel_spi
IntelSpiKind = apl
[PCI\VEN_8086&DEV_5AF0]
Plugin = intel_spi
IntelSpiKind = apl
[PCI\VEN_8086&DEV_A303]
Plugin = intel_spi
IntelSpiKind = pch300
[PCI\VEN_8086&DEV_A304]
Plugin = intel_spi
IntelSpiKind = pch300
[PCI\VEN_8086&DEV_A305]
Plugin = intel_spi
IntelSpiKind = pch300
[PCI\VEN_8086&DEV_A306]
Plugin = intel_spi
IntelSpiKind = pch300
[PCI\VEN_8086&DEV_A308]
Plugin = intel_spi
IntelSpiKind = pch300
[PCI\VEN_8086&DEV_A309]
Plugin = intel_spi
IntelSpiKind = pch300
[PCI\VEN_8086&DEV_A30A]
Plugin = intel_spi
IntelSpiKind = pch300
[PCI\VEN_8086&DEV_A30C]
Plugin = intel_spi
IntelSpiKind = pch300
[PCI\VEN_8086&DEV_A30D]
Plugin = intel_spi
IntelSpiKind = pch300
[PCI\VEN_8086&DEV_A30E]
Plugin = intel_spi
IntelSpiKind = pch300
[PCI\VEN_8086&DEV_3482]
Plugin = intel_spi
IntelSpiKind = pch300
[INTEL_SPI_CHIPSET\APL]
IntelSpiBarProxy = 00:0d.2
IntelSpiBiosCntl = 0xDC
Flags = PCH
[INTEL_SPI_CHIPSET\C620]
IntelSpiBarProxy = 00:1f.5
IntelSpiBiosCntl = 0xDC
Flags = PCH
[INTEL_SPI_CHIPSET\ICH0]
IntelSpiBiosCntl = 0x4E
Flags = ICH
[INTEL_SPI_CHIPSET\ICH2345]
IntelSpiBiosCntl = 0x4E
Flags = ICH
[INTEL_SPI_CHIPSET\ICH6]
IntelSpiBiosCntl = 0xDC
Flags = ICH
[INTEL_SPI_CHIPSET\PCH100]
IntelSpiBarProxy = 00:1f.5
IntelSpiBiosCntl = 0xDC
Flags = PCH
[INTEL_SPI_CHIPSET\PCH300]
IntelSpiBarProxy = 00:1f.5
IntelSpiBiosCntl = 0xDC
Flags = PCH
[INTEL_SPI_CHIPSET\PCH400]
IntelSpiBarProxy = 00:1f.5
IntelSpiBiosCntl = 0xDC
Flags = PCH
[INTEL_SPI_CHIPSET\POULSBO]
IntelSpiBiosCntl = 0xD8
Flags = ICH

View File

@ -1,6 +1,10 @@
if get_option('plugin_intel_spi')
cargs = ['-DG_LOG_DOMAIN="FuPluginIntelSpi"']
install_data(['intel-spi.quirk'],
install_dir: join_paths(datadir, 'fwupd', 'quirks.d')
)
shared_module('fu_plugin_intel_spi',
fu_hash,
sources : [
@ -12,8 +16,12 @@ shared_module('fu_plugin_intel_spi',
'fu-efi-firmware-volume.c', # fuzzing
'fu-ifd-bios.c', # fuzzing
'fu-ifd-common.c', # fuzzing
'fu-ifd-device.c',
'fu-ifd-firmware.c', # fuzzing
'fu-ifd-image.c', # fuzzing
'fu-intel-spi-common.c',
'fu-intel-spi-device.c',
'fu-pci-device.c',
'fu-plugin-intel-spi.c',
],
include_directories : [

View File

@ -27,6 +27,10 @@ fu_security_attr_get_name (FwupdSecurityAttr *attr)
/* TRANSLATORS: Title: SPI refers to the flash chip in the computer */
return g_strdup (_("SPI BIOS region"));
}
if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR) == 0) {
/* TRANSLATORS: Title: SPI refers to the flash chip in the computer */
return g_strdup (_("SPI BIOS Descriptor"));
}
if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_ACPI_DMAR) == 0) {
/* TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack */
return g_strdup (_("Pre-boot DMA protection"));