mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-03 19:51:33 +00:00
Support loading DMI data from DT systems
To do this with the existing codebase just fake the required SMBIOS structures.
This commit is contained in:
parent
1a61258239
commit
10c3fd2ff9
1
data/tests/devicetree/base/ibm,firmware-versions/version
Normal file
1
data/tests/devicetree/base/ibm,firmware-versions/version
Normal file
@ -0,0 +1 @@
|
||||
1.2.3-4
|
1
data/tests/devicetree/base/model
Normal file
1
data/tests/devicetree/base/model
Normal file
@ -0,0 +1 @@
|
||||
ColorHug
|
1
data/tests/devicetree/base/model-name
Normal file
1
data/tests/devicetree/base/model-name
Normal file
@ -0,0 +1 @@
|
||||
To Be Filled By O.E.M.
|
BIN
data/tests/devicetree/base/name
Normal file
BIN
data/tests/devicetree/base/name
Normal file
Binary file not shown.
1
data/tests/devicetree/base/vendor
Normal file
1
data/tests/devicetree/base/vendor
Normal file
@ -0,0 +1 @@
|
||||
Hughski Limited
|
BIN
data/tests/devicetree/base/vpd/name
Normal file
BIN
data/tests/devicetree/base/vpd/name
Normal file
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
||||
PCB-CH001
|
@ -0,0 +1 @@
|
||||
Richard Hughes
|
Binary file not shown.
BIN
data/tests/devicetree/base/vpd/root-node-vpd@a000/name
Normal file
BIN
data/tests/devicetree/base/vpd/root-node-vpd@a000/name
Normal file
Binary file not shown.
@ -275,6 +275,31 @@ fu_smbios3_func (void)
|
||||
g_assert_cmpstr (str, ==, "Dell Inc.");
|
||||
}
|
||||
|
||||
static void
|
||||
fu_smbios_dt_func (void)
|
||||
{
|
||||
const gchar *str;
|
||||
gboolean ret;
|
||||
g_autofree gchar *path = NULL;
|
||||
g_autoptr(FuSmbios) smbios = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
path = g_build_filename (TESTDATADIR_SRC, "devicetree", "base", NULL);
|
||||
smbios = fu_smbios_new ();
|
||||
ret = fu_smbios_setup_from_path (smbios, path, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (ret);
|
||||
if (g_getenv ("VERBOSE") != NULL) {
|
||||
g_autofree gchar *dump = fu_smbios_to_string (smbios);
|
||||
g_debug ("%s", dump);
|
||||
}
|
||||
|
||||
/* get vendor */
|
||||
str = fu_smbios_get_string (smbios, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x04, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_cmpstr (str, ==, "Hughski Limited");
|
||||
}
|
||||
|
||||
static void
|
||||
fu_hwids_func (void)
|
||||
{
|
||||
@ -2068,6 +2093,7 @@ main (int argc, char **argv)
|
||||
g_test_add_func ("/fwupd/hwids", fu_hwids_func);
|
||||
g_test_add_func ("/fwupd/smbios", fu_smbios_func);
|
||||
g_test_add_func ("/fwupd/smbios3", fu_smbios3_func);
|
||||
g_test_add_func ("/fwupd/smbios{dt}", fu_smbios_dt_func);
|
||||
g_test_add_func ("/fwupd/firmware", fu_firmware_func);
|
||||
g_test_add_func ("/fwupd/firmware{dedupe}", fu_firmware_dedupe_func);
|
||||
g_test_add_func ("/fwupd/firmware{build}", fu_firmware_build_func);
|
||||
|
@ -64,12 +64,71 @@ typedef struct __attribute__((packed)) {
|
||||
typedef struct {
|
||||
guint8 type;
|
||||
guint16 handle;
|
||||
GBytes *data;
|
||||
GByteArray *buf;
|
||||
GPtrArray *strings;
|
||||
} FuSmbiosItem;
|
||||
|
||||
G_DEFINE_TYPE (FuSmbios, fu_smbios, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
fu_smbios_convert_dt_string (FuSmbios *self, guint8 type, guint8 offset,
|
||||
const gchar *path, const gchar *subpath)
|
||||
{
|
||||
FuSmbiosItem *item = g_ptr_array_index (self->items, type);
|
||||
gsize bufsz = 0;
|
||||
g_autofree gchar *fn = g_build_filename (path, subpath, NULL);
|
||||
g_autofree gchar *buf = NULL;
|
||||
|
||||
/* not found */
|
||||
if (!g_file_get_contents (fn, &buf, &bufsz, NULL))
|
||||
return;
|
||||
|
||||
/* add to strtab */
|
||||
g_ptr_array_add (item->strings, g_strndup (buf, bufsz));
|
||||
for (guint i = item->buf->len; i < (guint) offset + 1; i++)
|
||||
fu_byte_array_append_uint8 (item->buf, 0x0);
|
||||
item->buf->data[offset] = item->strings->len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_smbios_setup_from_path_dt (FuSmbios *self, const gchar *path, GError **error)
|
||||
{
|
||||
/* add all four faked structures */
|
||||
for (guint i = 0; i < FU_SMBIOS_STRUCTURE_TYPE_LAST; i++) {
|
||||
FuSmbiosItem *item = g_new0 (FuSmbiosItem, 1);
|
||||
item->type = i;
|
||||
item->buf = g_byte_array_new ();
|
||||
item->strings = g_ptr_array_new_with_free_func (g_free);
|
||||
g_ptr_array_add (self->items, item);
|
||||
}
|
||||
|
||||
/* DMI:Manufacturer */
|
||||
fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x04,
|
||||
path, "vendor");
|
||||
|
||||
/* DMI:Family */
|
||||
fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x1a,
|
||||
path, "model-name");
|
||||
|
||||
/* DMI:ProductName */
|
||||
fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x05,
|
||||
path, "model");
|
||||
|
||||
/* DMI:BiosVersion */
|
||||
fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0x05,
|
||||
path, "ibm,firmware-versions/version");
|
||||
|
||||
/* DMI:BaseboardManufacturer */
|
||||
fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD, 0x04,
|
||||
path, "vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor");
|
||||
|
||||
/* DMI:BaseboardProduct */
|
||||
fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD, 0x05,
|
||||
path, "vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_smbios_setup_from_data (FuSmbios *self, const guint8 *buf, gsize sz, GError **error)
|
||||
{
|
||||
@ -93,8 +152,9 @@ fu_smbios_setup_from_data (FuSmbios *self, const guint8 *buf, gsize sz, GError *
|
||||
item = g_new0 (FuSmbiosItem, 1);
|
||||
item->type = str->type;
|
||||
item->handle = GUINT16_FROM_LE (str->handle);
|
||||
item->data = g_bytes_new (buf + i, str->len);
|
||||
item->buf = g_byte_array_sized_new (str->len);
|
||||
item->strings = g_ptr_array_new_with_free_func (g_free);
|
||||
g_byte_array_append (item->buf, buf + i, str->len);
|
||||
g_ptr_array_add (self->items, item);
|
||||
|
||||
/* jump to the end of the struct */
|
||||
@ -135,6 +195,17 @@ fu_smbios_setup_from_file (FuSmbios *self, const gchar *filename, GError **error
|
||||
{
|
||||
gsize sz = 0;
|
||||
g_autofree gchar *buf = NULL;
|
||||
g_autofree gchar *basename = NULL;
|
||||
|
||||
g_return_val_if_fail (FU_IS_SMBIOS (self), FALSE);
|
||||
g_return_val_if_fail (filename != NULL, FALSE);
|
||||
|
||||
/* use a heuristic */
|
||||
basename = g_path_get_basename (filename);
|
||||
if (g_strcmp0 (basename, "base") == 0)
|
||||
return fu_smbios_setup_from_path_dt (self, filename, error);
|
||||
|
||||
/* DMI blob */
|
||||
if (!g_file_get_contents (filename, &buf, &sz, error))
|
||||
return FALSE;
|
||||
return fu_smbios_setup_from_data (self, (guint8 *) buf, sz, error);
|
||||
@ -229,20 +300,8 @@ fu_smbios_parse_ep64 (FuSmbios *self, const gchar *buf, gsize sz, GError **error
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_smbios_setup_from_path:
|
||||
* @self: A #FuSmbios
|
||||
* @path: A path, e.g. `/sys/firmware/dmi/tables`
|
||||
* @error: A #GError or %NULL
|
||||
*
|
||||
* Reads all the SMBIOS values from a specific path.
|
||||
*
|
||||
* Returns: %TRUE for success
|
||||
*
|
||||
* Since: 1.0.0
|
||||
**/
|
||||
gboolean
|
||||
fu_smbios_setup_from_path (FuSmbios *self, const gchar *path, GError **error)
|
||||
static gboolean
|
||||
fu_smbios_setup_from_path_dmi (FuSmbios *self, const gchar *path, GError **error)
|
||||
{
|
||||
gsize sz = 0;
|
||||
g_autofree gchar *dmi_fn = NULL;
|
||||
@ -304,6 +363,33 @@ fu_smbios_setup_from_path (FuSmbios *self, const gchar *path, GError **error)
|
||||
return fu_smbios_setup_from_data (self, (guint8 *) dmi_raw, sz, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_smbios_setup_from_path:
|
||||
* @self: A #FuSmbios
|
||||
* @path: A path, e.g. `/sys/firmware/dmi/tables`
|
||||
* @error: A #GError or %NULL
|
||||
*
|
||||
* Reads all the SMBIOS values from a specific path.
|
||||
*
|
||||
* Returns: %TRUE for success
|
||||
*
|
||||
* Since: 1.0.0
|
||||
**/
|
||||
gboolean
|
||||
fu_smbios_setup_from_path (FuSmbios *self, const gchar *path, GError **error)
|
||||
{
|
||||
g_autofree gchar *basename = NULL;
|
||||
|
||||
g_return_val_if_fail (FU_IS_SMBIOS (self), FALSE);
|
||||
g_return_val_if_fail (path != NULL, FALSE);
|
||||
|
||||
/* use a heuristic */
|
||||
basename = g_path_get_basename (path);
|
||||
if (g_strcmp0 (basename, "base") == 0)
|
||||
return fu_smbios_setup_from_path_dt (self, path, error);
|
||||
return fu_smbios_setup_from_path_dmi (self, path, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_smbios_setup:
|
||||
* @self: A #FuSmbios
|
||||
@ -319,11 +405,30 @@ gboolean
|
||||
fu_smbios_setup (FuSmbios *self, GError **error)
|
||||
{
|
||||
g_autofree gchar *path = NULL;
|
||||
g_autofree gchar *path_dt = NULL;
|
||||
g_autofree gchar *sysfsfwdir = NULL;
|
||||
|
||||
g_return_val_if_fail (FU_IS_SMBIOS (self), FALSE);
|
||||
|
||||
sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW);
|
||||
|
||||
/* DMI */
|
||||
path = g_build_filename (sysfsfwdir, "dmi", "tables", NULL);
|
||||
return fu_smbios_setup_from_path (self, path, error);
|
||||
if (g_file_test (path, G_FILE_TEST_EXISTS))
|
||||
return fu_smbios_setup_from_path (self, path, error);
|
||||
|
||||
/* DT */
|
||||
path_dt = g_build_filename (sysfsfwdir, "devicetree", "base", NULL);
|
||||
if (g_file_test (path_dt, G_FILE_TEST_EXISTS))
|
||||
return fu_smbios_setup_from_path (self, path_dt, error);
|
||||
|
||||
/* neither found */
|
||||
g_set_error_literal (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INVALID_FILE,
|
||||
"neither SMBIOS or DT found");
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -348,8 +453,7 @@ fu_smbios_to_string (FuSmbios *self)
|
||||
for (guint i = 0; i < self->items->len; i++) {
|
||||
FuSmbiosItem *item = g_ptr_array_index (self->items, i);
|
||||
g_string_append_printf (str, "Type: %02x\n", item->type);
|
||||
g_string_append_printf (str, " Length: %" G_GSIZE_FORMAT "\n",
|
||||
g_bytes_get_size (item->data));
|
||||
g_string_append_printf (str, " Length: %u\n", item->buf->len);
|
||||
g_string_append_printf (str, " Handle: 0x%04x\n", item->handle);
|
||||
for (guint j = 0; j < item->strings->len; j++) {
|
||||
const gchar *tmp = g_ptr_array_index (item->strings, j);
|
||||
@ -395,7 +499,7 @@ fu_smbios_get_data (FuSmbios *self, guint8 type, GError **error)
|
||||
"no structure with type %02x", type);
|
||||
return NULL;
|
||||
}
|
||||
return g_bytes_ref (item->data);
|
||||
return g_bytes_new (item->buf->data, item->buf->len);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -418,8 +522,6 @@ const gchar *
|
||||
fu_smbios_get_string (FuSmbios *self, guint8 type, guint8 offset, GError **error)
|
||||
{
|
||||
FuSmbiosItem *item;
|
||||
const guint8 *data;
|
||||
gsize sz;
|
||||
|
||||
g_return_val_if_fail (FU_IS_SMBIOS (self), NULL);
|
||||
|
||||
@ -434,15 +536,15 @@ fu_smbios_get_string (FuSmbios *self, guint8 type, guint8 offset, GError **error
|
||||
}
|
||||
|
||||
/* check offset valid */
|
||||
data = g_bytes_get_data (item->data, &sz);
|
||||
if (offset >= sz) {
|
||||
if (offset >= item->buf->len) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INVALID_FILE,
|
||||
"offset bigger than size %" G_GSIZE_FORMAT, sz);
|
||||
"offset bigger than size %u",
|
||||
item->buf->len);
|
||||
return NULL;
|
||||
}
|
||||
if (data[offset] == 0x00) {
|
||||
if (item->buf->data[offset] == 0x00) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_FOUND,
|
||||
@ -451,21 +553,21 @@ fu_smbios_get_string (FuSmbios *self, guint8 type, guint8 offset, GError **error
|
||||
}
|
||||
|
||||
/* check string index valid */
|
||||
if (data[offset] > item->strings->len) {
|
||||
if (item->buf->data[offset] > item->strings->len) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INVALID_FILE,
|
||||
"index larger than string table %u",
|
||||
data[offset]);
|
||||
item->strings->len);
|
||||
return NULL;
|
||||
}
|
||||
return g_ptr_array_index (item->strings, data[offset] - 1);
|
||||
return g_ptr_array_index (item->strings, item->buf->data[offset] - 1);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_smbios_item_free (FuSmbiosItem *item)
|
||||
{
|
||||
g_bytes_unref (item->data);
|
||||
g_byte_array_unref (item->buf);
|
||||
g_ptr_array_unref (item->strings);
|
||||
g_free (item);
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ FuSmbios *fu_smbios_new (void);
|
||||
#define FU_SMBIOS_STRUCTURE_TYPE_SYSTEM 0x01
|
||||
#define FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD 0x02
|
||||
#define FU_SMBIOS_STRUCTURE_TYPE_CHASSIS 0x03
|
||||
#define FU_SMBIOS_STRUCTURE_TYPE_LAST 0x04
|
||||
|
||||
gchar *fu_smbios_to_string (FuSmbios *self);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user