mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-11 22:30:47 +00:00
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:
parent
b333e0045c
commit
f3c64adb6c
16
docs/hsi.xml
16
docs/hsi.xml
@ -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>
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
155
plugins/intel-spi/fu-ifd-device.c
Normal file
155
plugins/intel-spi/fu-ifd-device.c
Normal 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);
|
||||
}
|
24
plugins/intel-spi/fu-ifd-device.h
Normal file
24
plugins/intel-spi/fu-ifd-device.h
Normal 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);
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
101
plugins/intel-spi/fu-intel-spi-common.c
Normal file
101
plugins/intel-spi/fu-intel-spi-common.c
Normal 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));
|
||||
}
|
85
plugins/intel-spi/fu-intel-spi-common.h
Normal file
85
plugins/intel-spi/fu-intel-spi-common.h
Normal 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);
|
506
plugins/intel-spi/fu-intel-spi-device.c
Normal file
506
plugins/intel-spi/fu-intel-spi-device.c
Normal 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;
|
||||
}
|
18
plugins/intel-spi/fu-intel-spi-device.h
Normal file
18
plugins/intel-spi/fu-intel-spi-device.h
Normal 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);
|
175
plugins/intel-spi/fu-pci-device.c
Normal file
175
plugins/intel-spi/fu-pci-device.c
Normal 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));
|
||||
}
|
22
plugins/intel-spi/fu-pci-device.h
Normal file
22
plugins/intel-spi/fu-pci-device.h
Normal 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);
|
@ -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;
|
||||
}
|
||||
|
76
plugins/intel-spi/generate-quirk.py
Executable file
76
plugins/intel-spi/generate-quirk.py
Executable 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))
|
401
plugins/intel-spi/intel-spi.quirk
Normal file
401
plugins/intel-spi/intel-spi.quirk
Normal 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
|
@ -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 : [
|
||||
|
@ -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"));
|
||||
|
Loading…
Reference in New Issue
Block a user