fwupd/plugins/pci-bcr/fu-plugin-pci-bcr.c
Richard Hughes b333e0045c Split out a shared system context
There is a lot of code in fwupd that just assigns a shared object type to
a FuPlugin, and then for each device on that plugin assigns that same shared
object to each FuDevice.

Rather than proxy several kinds of information stores over two different levels
of abstraction create a 'context' which contains the shared *system* state
between the daemon, the plugins and the daemon.

This will allow us to hold other per-machine state in the future, for instance
the system battery level or AC state.
2021-04-01 21:11:29 +01:00

209 lines
5.9 KiB
C

/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include "fu-plugin-vfuncs.h"
struct FuPluginData {
gboolean has_device;
guint8 bcr_addr;
guint8 bcr;
};
#define BCR_WPD (1 << 0)
#define BCR_BLE (1 << 1)
#define BCR_SMM_BWP (1 << 5)
void
fu_plugin_init (FuPlugin *plugin)
{
FuContext *ctx = fu_plugin_get_context (plugin);
FuPluginData *priv = fu_plugin_alloc_data (plugin, sizeof (FuPluginData));
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
fu_context_add_udev_subsystem (ctx, "pci");
fu_context_add_quirk_key (ctx, "PciBcrAddr");
/* this is true except for some Atoms */
priv->bcr_addr = 0xdc;
}
static void
fu_plugin_pci_bcr_set_updatable (FuPlugin *plugin, FuDevice *dev)
{
FuPluginData *priv = fu_plugin_get_data (plugin);
if ((priv->bcr & BCR_WPD) == 0 && (priv->bcr & BCR_BLE) > 0) {
fu_device_remove_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_set_update_error (dev, "BIOS locked");
}
}
void
fu_plugin_device_registered (FuPlugin *plugin, FuDevice *dev)
{
FuPluginData *priv = fu_plugin_get_data (plugin);
if (g_strcmp0 (fu_device_get_plugin (dev), "cpu") == 0 ||
g_strcmp0 (fu_device_get_plugin (dev), "flashrom") == 0) {
guint tmp = fu_device_get_metadata_integer (dev, "PciBcrAddr");
if (tmp != G_MAXUINT && priv->bcr_addr != tmp) {
g_debug ("overriding BCR addr from 0x%02x to 0x%02x",
priv->bcr_addr, tmp);
priv->bcr_addr = tmp;
}
}
if (g_strcmp0 (fu_device_get_plugin (dev), "flashrom") == 0 &&
fu_device_has_instance_id (dev, "main-system-firmware")) {
/* PCI\VEN_8086 added first */
if (priv->has_device) {
fu_plugin_pci_bcr_set_updatable (plugin, dev);
return;
}
fu_plugin_cache_add (plugin, "main-system-firmware", dev);
}
}
static void
fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs)
{
FuPluginData *priv = fu_plugin_get_data (plugin);
g_autoptr(FwupdSecurityAttr) attr = NULL;
/* create attr */
attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE);
fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin));
fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL);
fu_security_attrs_append (attrs, attr);
/* no device */
if (!priv->has_device) {
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND);
return;
}
/* load file */
if ((priv->bcr & BCR_WPD) == 1) {
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED);
return;
}
/* success */
fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
}
static void
fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs)
{
FuPluginData *priv = fu_plugin_get_data (plugin);
g_autoptr(FwupdSecurityAttr) attr = NULL;
/* no device */
if (!priv->has_device)
return;
/* create attr */
attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BLE);
fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin));
fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL);
fu_security_attrs_append (attrs, attr);
/* load file */
if ((priv->bcr & BCR_BLE) == 0) {
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
return;
}
/* success */
fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED);
}
static void
fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs)
{
FuPluginData *priv = fu_plugin_get_data (plugin);
g_autoptr(FwupdSecurityAttr) attr = NULL;
/* no device */
if (!priv->has_device)
return;
/* create attr */
attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP);
fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin));
fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL);
fu_security_attrs_append (attrs, attr);
/* load file */
if ((priv->bcr & BCR_SMM_BWP) == 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);
}
gboolean
fu_plugin_backend_device_added (FuPlugin *plugin, FuDevice *device, GError **error)
{
FuPluginData *priv = fu_plugin_get_data (plugin);
FuDevice *device_msf;
g_autoptr(FuDeviceLocker) locker = NULL;
/* not supported */
if (priv->bcr_addr == 0x0) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"BCR not supported on this platform");
return FALSE;
}
/* interesting device? */
if (!FU_IS_UDEV_DEVICE (device))
return TRUE;
if (g_strcmp0 (fu_udev_device_get_subsystem (FU_UDEV_DEVICE (device)), "pci") != 0)
return TRUE;
/* open the config */
fu_udev_device_set_flags (FU_UDEV_DEVICE (device), FU_UDEV_DEVICE_FLAG_USE_CONFIG);
if (!fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "pci", error))
return FALSE;
locker = fu_device_locker_new (device, error);
if (locker == NULL)
return FALSE;
/* grab BIOS Control Register */
if (!fu_udev_device_pread (FU_UDEV_DEVICE (device), priv->bcr_addr, &priv->bcr, error)) {
g_prefix_error (error, "could not read BCR: ");
return FALSE;
}
/* main-system-firmware device added first, probably from flashrom */
device_msf = fu_plugin_cache_lookup (plugin, "main-system-firmware");
if (device_msf != NULL)
fu_plugin_pci_bcr_set_updatable (plugin, device_msf);
/* success */
priv->has_device = TRUE;
return TRUE;
}
void
fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs)
{
/* only Intel */
if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL)
return;
/* add attrs */
fu_plugin_add_security_attr_bioswe (plugin, attrs);
fu_plugin_add_security_attr_ble (plugin, attrs);
fu_plugin_add_security_attr_smm_bwp (plugin, attrs);
}