fwupd/plugins/dell-esrt/fu-plugin-dell-esrt.c
Mario Limonciello 75835b4a0b Use FWUPD_COMPILATION define to indicate an in tree build
When this is done, include:
* Including the hash
* Including anything that is not ABI stable in plugins yet

Suggested-by: Simon McVittie <smcv@debian.org>
2021-01-22 14:01:25 -06:00

179 lines
4.8 KiB
C

/*
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2017 Dell, Inc.
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <smbios_c/token.h>
#include <smbios_c/smi.h>
#include "fu-plugin-vfuncs.h"
/* allowed smbios class/select commands */
#define CLASS_ADMIN_PROP 10
#define SELECT_ADMIN_PROP 3
/* allowed tokens */
#define CAPSULE_EN_TOKEN 0x0461
#define CAPSULE_DIS_TOKEN 0x0462
/* these aren't defined upstream but used in fwupdate */
#define DELL_ADMIN_MASK 0xF
#define DELL_ADMIN_INSTALLED 0
static gboolean
fu_plugin_dell_esrt_query_token (guint16 token, gboolean *value, GError **error)
{
if (!token_is_bool (token)) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"token %" G_GUINT16_FORMAT " is not boolean",
token);
return FALSE;
}
if (value != NULL)
*value = token_is_active (token) > 0;
return TRUE;
}
static gboolean
fu_plugin_dell_esrt_activate_token (guint16 token, GError **error)
{
token_activate (token);
if (token_is_active (token) < 0) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"token %" G_GUINT16_FORMAT "cannot be activated "
"as the password is set", token);
return FALSE;
}
return TRUE;
}
static gboolean
fu_plugin_dell_esrt_admin_password_present (gboolean *password_present, GError **error)
{
guint32 args[4] = { 0, }, out[4] = { 0, };
if (dell_simple_ci_smi (CLASS_ADMIN_PROP,
SELECT_ADMIN_PROP, args, out)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"cannot call SMI for CLASS_ADMIN_PROP");
return FALSE;
}
if (out[0] != 0 || (out[1] & DELL_ADMIN_MASK) == DELL_ADMIN_INSTALLED) {
*password_present = TRUE;
} else {
*password_present = FALSE;
}
return TRUE;
}
void
fu_plugin_init (FuPlugin *plugin)
{
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "bios");
}
gboolean
fu_plugin_startup (FuPlugin *plugin, GError **error)
{
gboolean capsule_disable = FALSE;
g_autofree gchar *sysfsfwdir = NULL;
g_autofree gchar *esrtdir = NULL;
/* already exists */
sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW);
esrtdir = g_build_filename (sysfsfwdir, "efi", "esrt", NULL);
if (g_file_test (esrtdir, G_FILE_TEST_EXISTS)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"UEFI firmware already supported");
return FALSE;
}
/* is the capsule functionality disabled */
if (!fu_plugin_dell_esrt_query_token (CAPSULE_DIS_TOKEN, &capsule_disable, error))
return FALSE;
if (!capsule_disable) {
gboolean capsule_enable = FALSE;
if (!fu_plugin_dell_esrt_query_token (CAPSULE_EN_TOKEN, &capsule_enable, error))
return FALSE;
if (capsule_enable) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"UEFI firmware will be unlocked on next boot");
return FALSE;
}
}
return TRUE;
}
gboolean
fu_plugin_unlock (FuPlugin *plugin, FuDevice *device, GError **error)
{
gboolean password_present = FALSE;
/* check the admin password isn't set */
if (!fu_plugin_dell_esrt_admin_password_present (&password_present, error))
return FALSE;
if (password_present) {
const gchar *err_string = "Cannot be unlocked automatically as admin password set";
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
err_string);
fu_device_set_update_error (device, err_string);
return FALSE;
}
/* disabled in BIOS, but supported to be enabled via tool */
if (!fu_plugin_dell_esrt_query_token (CAPSULE_EN_TOKEN, NULL, error))
return FALSE;
if (!fu_plugin_dell_esrt_activate_token (CAPSULE_EN_TOKEN, error))
return FALSE;
fu_device_set_update_error (device, NULL);
return TRUE;
}
gboolean
fu_plugin_coldplug (FuPlugin *plugin, GError **error)
{
g_autoptr(FuDevice) dev = fu_device_new ();
/* create a dummy device so we can unlock the feature */
fu_device_set_id (dev, "UEFI-dummy");
fu_device_set_name (dev, "Dell UEFI updates");
fu_device_set_summary (dev, "Enable UEFI Update Functionality");
fu_device_add_vendor_id (dev, "PCI:0x1028");
fu_device_add_instance_id (dev, "main-system-firmware");
fu_device_add_guid (dev, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e");
fu_device_set_version_format (dev, FWUPD_VERSION_FORMAT_NUMBER);
fu_device_set_version (dev, "0");
fu_device_add_icon (dev, "computer");
fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_LOCKED);
fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT);
fu_device_set_update_error (dev, "Firmware updates disabled; run 'fwupdmgr unlock' to enable");
if (!fu_device_setup (dev, error))
return FALSE;
fu_plugin_device_add (plugin, dev);
return TRUE;
}