mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-05 07:00:30 +00:00
cpu: Directly probe the CPUID data to improve startup speed
This is much more efficient than parsing hundreds of lines of /proc/cpuinfo and also causes hundreds of thousands less allocations at startup. For systems with dozens of virtual CPUs the deduplication of device objects was increasing start up time considerably. Use the msr plugin to read the microcode version as this is not obtained using CPUID, as it is instead being provided in an MSR.
This commit is contained in:
parent
f779a0cfaa
commit
8307bd603e
@ -93,56 +93,6 @@ fu_cpu_device_convert_vendor (const gchar *vendor)
|
||||
return vendor;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_cpu_device_parse_flags (FuCpuDevice *self, const gchar *data)
|
||||
{
|
||||
g_auto(GStrv) flags = g_strsplit (data, " ", -1);
|
||||
for (guint i = 0; flags[i] != NULL; i++) {
|
||||
if (g_strcmp0 (flags[i], "shstk") == 0)
|
||||
self->flags |= FU_CPU_DEVICE_FLAG_SHSTK;
|
||||
if (g_strcmp0 (flags[i], "ibt") == 0)
|
||||
self->flags |= FU_CPU_DEVICE_FLAG_IBT;
|
||||
if (g_strcmp0 (flags[i], "tme") == 0)
|
||||
self->flags |= FU_CPU_DEVICE_FLAG_TME;
|
||||
if (g_strcmp0 (flags[i], "smap") == 0)
|
||||
self->flags |= FU_CPU_DEVICE_FLAG_SMAP;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fu_cpu_device_parse_section (FuDevice *dev, const gchar *data)
|
||||
{
|
||||
g_auto(GStrv) lines = NULL;
|
||||
FuCpuDevice *self = FU_CPU_DEVICE (dev);
|
||||
|
||||
lines = g_strsplit (data, "\n", 0);
|
||||
for (guint i = 0; lines[i] != NULL; i++) {
|
||||
if (g_str_has_prefix (lines[i], "vendor_id")) {
|
||||
g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1);
|
||||
if (fields[1] != NULL)
|
||||
fu_device_set_vendor (dev, fu_cpu_device_convert_vendor (fields[1] + 1));
|
||||
} else if (g_str_has_prefix (lines[i], "model name")) {
|
||||
g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1);
|
||||
if (fields[1] != NULL)
|
||||
fu_device_set_name (dev, g_strchug (fields[1]));
|
||||
} else if (g_str_has_prefix (lines[i], "microcode")) {
|
||||
g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1);
|
||||
if (fields[1] != NULL)
|
||||
fu_device_set_version (dev, g_strchug (fields[1]));
|
||||
} else if (g_str_has_prefix (lines[i], "physical id")) {
|
||||
g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1);
|
||||
if (fields[1] != NULL) {
|
||||
g_autofree gchar *tmp = g_strdup_printf ("cpu:%s", g_strchug (fields[1]));
|
||||
fu_device_set_physical_id (dev, tmp);
|
||||
}
|
||||
} else if (g_str_has_prefix (lines[i], "flags")) {
|
||||
g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1);
|
||||
if (fields[1] != NULL)
|
||||
fu_cpu_device_parse_flags (self, fields[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fu_cpu_device_init (FuCpuDevice *self)
|
||||
{
|
||||
@ -150,6 +100,7 @@ fu_cpu_device_init (FuCpuDevice *self)
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL);
|
||||
fu_device_add_icon (FU_DEVICE (self), "computer");
|
||||
fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_HEX);
|
||||
fu_device_set_physical_id (FU_DEVICE (self), "cpu:0");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -200,9 +151,93 @@ fu_cpu_device_add_instance_ids (FuDevice *device, GError **error)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_cpu_device_probe_manufacturer_id (FuDevice *device, GError **error)
|
||||
{
|
||||
guint32 ebx = 0;
|
||||
guint32 ecx = 0;
|
||||
guint32 edx = 0;
|
||||
gchar str[13] = { '\0' };
|
||||
if (!fu_common_cpuid (0x0, NULL, &ebx, &ecx, &edx, error))
|
||||
return FALSE;
|
||||
if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), 0x0, /* dst */
|
||||
(const guint8 *) &ebx, sizeof(ebx), 0x0, /* src */
|
||||
sizeof(guint32), error))
|
||||
return FALSE;
|
||||
if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), 0x4, /* dst */
|
||||
(const guint8 *) &edx, sizeof(edx), 0x0, /* src */
|
||||
sizeof(guint32), error))
|
||||
return FALSE;
|
||||
if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), 0x8, /* dst */
|
||||
(const guint8 *) &ecx, sizeof(ecx), 0x0, /* src */
|
||||
sizeof(guint32), error))
|
||||
return FALSE;
|
||||
fu_device_set_vendor (device, fu_cpu_device_convert_vendor (str));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_cpu_device_probe_model (FuDevice *device, GError **error)
|
||||
{
|
||||
guint32 eax = 0;
|
||||
guint32 ebx = 0;
|
||||
guint32 ecx = 0;
|
||||
guint32 edx = 0;
|
||||
gchar str[49] = { '\0' };
|
||||
|
||||
for (guint32 i = 0; i < 3; i++) {
|
||||
if (!fu_common_cpuid (0x80000002 + i, &eax, &ebx, &ecx, &edx, error))
|
||||
return FALSE;
|
||||
if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0x0, /* dst */
|
||||
(const guint8 *) &eax, sizeof(eax), 0x0, /* src */
|
||||
sizeof(guint32), error))
|
||||
return FALSE;
|
||||
if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0x4, /* dst */
|
||||
(const guint8 *) &ebx, sizeof(ebx), 0x0, /* src */
|
||||
sizeof(guint32), error))
|
||||
return FALSE;
|
||||
if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0x8, /* dst */
|
||||
(const guint8 *) &ecx, sizeof(ecx), 0x0, /* src */
|
||||
sizeof(guint32), error))
|
||||
return FALSE;
|
||||
if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0xc, /* dst */
|
||||
(const guint8 *) &edx, sizeof(edx), 0x0, /* src */
|
||||
sizeof(guint32), error))
|
||||
return FALSE;
|
||||
}
|
||||
fu_device_set_name (device, str);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_cpu_device_probe_extended_features (FuDevice *device, GError **error)
|
||||
{
|
||||
FuCpuDevice *self = FU_CPU_DEVICE (device);
|
||||
guint32 ebx = 0;
|
||||
guint32 ecx = 0;
|
||||
|
||||
if (!fu_common_cpuid (0x7, NULL, &ebx, &ecx, NULL, error))
|
||||
return FALSE;
|
||||
if ((ebx >> 20) & 0x1)
|
||||
self->flags |= FU_CPU_DEVICE_FLAG_SMAP;
|
||||
if ((ecx >> 7) & 0x1)
|
||||
self->flags |= FU_CPU_DEVICE_FLAG_SHSTK;
|
||||
if ((ecx >> 13) & 0x1)
|
||||
self->flags |= FU_CPU_DEVICE_FLAG_TME;
|
||||
if ((ecx >> 20) & 0x1)
|
||||
self->flags |= FU_CPU_DEVICE_FLAG_IBT;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_cpu_device_probe (FuDevice *device, GError **error)
|
||||
{
|
||||
if (!fu_cpu_device_probe_manufacturer_id (device, error))
|
||||
return FALSE;
|
||||
if (!fu_cpu_device_probe_model (device, error))
|
||||
return FALSE;
|
||||
if (!fu_cpu_device_probe_extended_features (device, error))
|
||||
return FALSE;
|
||||
if (!fu_cpu_device_add_instance_ids (device, error))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
@ -236,10 +271,9 @@ fu_cpu_device_class_init (FuCpuDeviceClass *klass)
|
||||
}
|
||||
|
||||
FuCpuDevice *
|
||||
fu_cpu_device_new (const gchar *section)
|
||||
fu_cpu_device_new (void)
|
||||
{
|
||||
FuCpuDevice *device = NULL;
|
||||
device = g_object_new (FU_TYPE_CPU_DEVICE, NULL);
|
||||
fu_cpu_device_parse_section (FU_DEVICE (device), section);
|
||||
return device;
|
||||
}
|
||||
|
@ -19,6 +19,6 @@ typedef enum {
|
||||
FU_CPU_DEVICE_FLAG_SMAP = 1 << 3,
|
||||
} FuCpuDeviceFlag;
|
||||
|
||||
FuCpuDevice *fu_cpu_device_new (const gchar *section);
|
||||
FuCpuDevice *fu_cpu_device_new (void);
|
||||
gboolean fu_cpu_device_has_flag (FuCpuDevice *self,
|
||||
FuCpuDeviceFlag flag);
|
||||
|
@ -10,58 +10,31 @@
|
||||
#include "fu-hash.h"
|
||||
#include "fu-cpu-device.h"
|
||||
|
||||
struct FuPluginData {
|
||||
gboolean has_cet;
|
||||
gboolean has_smap;
|
||||
gboolean has_tme;
|
||||
};
|
||||
|
||||
void
|
||||
fu_plugin_init (FuPlugin *plugin)
|
||||
{
|
||||
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
|
||||
fu_plugin_alloc_data (plugin, sizeof (FuPluginData));
|
||||
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "msr");
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_plugin_coldplug (FuPlugin *plugin, GError **error)
|
||||
{
|
||||
FuPluginData *data = fu_plugin_get_data (plugin);
|
||||
gsize length;
|
||||
g_autofree gchar *buf = NULL;
|
||||
g_auto(GStrv) lines = NULL;
|
||||
|
||||
if (!g_file_get_contents ("/proc/cpuinfo", &buf, &length, error))
|
||||
g_autoptr(FuCpuDevice) dev = fu_cpu_device_new ();
|
||||
fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin));
|
||||
if (!fu_device_probe (FU_DEVICE (dev), error))
|
||||
return FALSE;
|
||||
|
||||
lines = g_strsplit (buf, "\n\n", 0);
|
||||
for (guint i = 0; lines[i] != NULL; i++) {
|
||||
g_autoptr(FuCpuDevice) dev = NULL;
|
||||
if (strlen (lines[i]) == 0)
|
||||
continue;
|
||||
dev = fu_cpu_device_new (lines[i]);
|
||||
fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin));
|
||||
if (!fu_device_probe (FU_DEVICE (dev), error))
|
||||
return FALSE;
|
||||
if (!fu_device_setup (FU_DEVICE (dev), error))
|
||||
return FALSE;
|
||||
if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_SHSTK) &&
|
||||
fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_IBT))
|
||||
data->has_cet = TRUE;
|
||||
if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_TME))
|
||||
data->has_tme = TRUE;
|
||||
if (fu_cpu_device_has_flag (dev, FU_CPU_DEVICE_FLAG_SMAP))
|
||||
data->has_smap = TRUE;
|
||||
fu_plugin_device_add (plugin, FU_DEVICE (dev));
|
||||
}
|
||||
|
||||
if (!fu_device_setup (FU_DEVICE (dev), error))
|
||||
return FALSE;
|
||||
fu_plugin_cache_add (plugin, "cpu", dev);
|
||||
fu_plugin_device_add (plugin, FU_DEVICE (dev));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_plugin_add_security_attrs_intel_cet_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs)
|
||||
{
|
||||
FuPluginData *data = fu_plugin_get_data (plugin);
|
||||
FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu");
|
||||
g_autoptr(FwupdSecurityAttr) attr = NULL;
|
||||
|
||||
/* create attr */
|
||||
@ -71,7 +44,8 @@ fu_plugin_add_security_attrs_intel_cet_enabled (FuPlugin *plugin, FuSecurityAttr
|
||||
fu_security_attrs_append (attrs, attr);
|
||||
|
||||
/* check for CET */
|
||||
if (!data->has_cet) {
|
||||
if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_SHSTK) ||
|
||||
!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_IBT)) {
|
||||
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
@ -84,14 +58,15 @@ fu_plugin_add_security_attrs_intel_cet_enabled (FuPlugin *plugin, FuSecurityAttr
|
||||
static void
|
||||
fu_plugin_add_security_attrs_intel_cet_active (FuPlugin *plugin, FuSecurityAttrs *attrs)
|
||||
{
|
||||
FuPluginData *data = fu_plugin_get_data (plugin);
|
||||
FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu");
|
||||
gint exit_status = 0xff;
|
||||
g_autofree gchar *toolfn = NULL;
|
||||
g_autoptr(FwupdSecurityAttr) attr = NULL;
|
||||
g_autoptr(GError) error_local = NULL;
|
||||
|
||||
/* check for CET */
|
||||
if (!data->has_cet)
|
||||
if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_SHSTK) ||
|
||||
!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_IBT))
|
||||
return;
|
||||
|
||||
/* create attr */
|
||||
@ -120,7 +95,7 @@ fu_plugin_add_security_attrs_intel_cet_active (FuPlugin *plugin, FuSecurityAttrs
|
||||
static void
|
||||
fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs)
|
||||
{
|
||||
FuPluginData *data = fu_plugin_get_data (plugin);
|
||||
FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu");
|
||||
g_autoptr(FwupdSecurityAttr) attr = NULL;
|
||||
|
||||
/* create attr */
|
||||
@ -130,7 +105,7 @@ fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs
|
||||
fu_security_attrs_append (attrs, attr);
|
||||
|
||||
/* check for TME */
|
||||
if (!data->has_tme) {
|
||||
if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_TME)) {
|
||||
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
@ -143,7 +118,7 @@ fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs
|
||||
static void
|
||||
fu_plugin_add_security_attrs_intel_smap (FuPlugin *plugin, FuSecurityAttrs *attrs)
|
||||
{
|
||||
FuPluginData *data = fu_plugin_get_data (plugin);
|
||||
FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu");
|
||||
g_autoptr(FwupdSecurityAttr) attr = NULL;
|
||||
|
||||
/* create attr */
|
||||
@ -153,7 +128,7 @@ fu_plugin_add_security_attrs_intel_smap (FuPlugin *plugin, FuSecurityAttrs *attr
|
||||
fu_security_attrs_append (attrs, attr);
|
||||
|
||||
/* check for SMEP and SMAP */
|
||||
if (!data->has_smap) {
|
||||
if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_SMAP)) {
|
||||
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ struct FuPluginData {
|
||||
};
|
||||
|
||||
#define PCI_MSR_IA32_DEBUG_INTERFACE 0xc80
|
||||
#define PCI_MSR_IA32_BIOS_SIGN_ID 0x8b
|
||||
|
||||
void
|
||||
fu_plugin_init (FuPlugin *plugin)
|
||||
@ -52,6 +53,7 @@ fu_plugin_startup (FuPlugin *plugin, GError **error)
|
||||
gboolean
|
||||
fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error)
|
||||
{
|
||||
FuDevice *device_cpu = fu_plugin_cache_lookup (plugin, "cpu");
|
||||
FuPluginData *priv = fu_plugin_get_data (plugin);
|
||||
guint8 buf[8] = { 0x0 };
|
||||
g_autoptr(FuDeviceLocker) locker = NULL;
|
||||
@ -88,9 +90,43 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er
|
||||
priv->ia32_debug.fields.locked,
|
||||
priv->ia32_debug.fields.debug_occurred);
|
||||
}
|
||||
|
||||
/* get microcode version */
|
||||
if (device_cpu != NULL) {
|
||||
guint32 ver_raw;
|
||||
if (!fu_udev_device_pread_full (device, PCI_MSR_IA32_BIOS_SIGN_ID,
|
||||
buf, sizeof(buf), error)) {
|
||||
g_prefix_error (error, "could not read IA32_BIOS_SIGN_ID: ");
|
||||
return FALSE;
|
||||
}
|
||||
fu_common_dump_raw (G_LOG_DOMAIN, "IA32_BIOS_SIGN_ID", buf, sizeof(buf));
|
||||
if (!fu_common_read_uint32_safe (buf, sizeof(buf), 0x4,
|
||||
&ver_raw, G_LITTLE_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
if (ver_raw != 0) {
|
||||
FwupdVersionFormat verfmt = fu_device_get_version_format (device_cpu);
|
||||
g_autofree gchar *ver_str = NULL;
|
||||
ver_str = fu_common_version_from_uint32 (ver_raw, verfmt);
|
||||
g_debug ("setting microcode version to %s", ver_str);
|
||||
fu_device_set_version (device_cpu, ver_str);
|
||||
fu_device_set_version_raw (device_cpu, ver_raw);
|
||||
}
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
fu_plugin_device_registered (FuPlugin *plugin, FuDevice *dev)
|
||||
{
|
||||
if (g_strcmp0 (fu_device_get_plugin (dev), "cpu") == 0) {
|
||||
fu_plugin_cache_add (plugin, "cpu", dev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fu_plugin_add_security_attr_dci_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user