Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7b08217 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull DMI updates from Jean Delvare:
 "The most important change is the new sysfs interface to the DMI table,
  which will let user-space tools (such as dmidecode) access the table
  without relying on /dev/mem"

* 'dmi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  firmware: dmi: struct dmi_header should be packed
  firmware: dmi_scan: Coding style cleanups
  Documentation: ABI: sysfs-firmware-dmi: add -entries suffix to file name
  firmware: dmi_scan: add SBMIOS entry and DMI tables
  firmware: dmi_scan: Trim DMI table length before exporting it
  firmware: dmi_scan: Rename dmi_table to dmi_decode_table
  firmware: dmi: List my quilt tree
  firmware: dmi_scan: Only honor end-of-table for 64-bit tables
parents 64e22b86 9ea650c8
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
What:		/sys/firmware/dmi/
What:		/sys/firmware/dmi/entries/
Date:		February 2011
Date:		February 2011
Contact:	Mike Waychison <mikew@google.com>
Contact:	Mike Waychison <mikew@google.com>
Description:
Description:
+22 −0
Original line number Original line Diff line number Diff line
What:		/sys/firmware/dmi/tables/
Date:		April 2015
Contact:	Ivan Khoronzhuk <ivan.khoronzhuk@globallogic.com>
Description:
		The firmware provides DMI structures as a packed list of
		data referenced by a SMBIOS table entry point. The SMBIOS
		entry point contains general information, like SMBIOS
		version, DMI table size, etc. The structure, content and
		size of SMBIOS entry point is dependent on SMBIOS version.
		The format of SMBIOS entry point and DMI structures
		can be read in SMBIOS specification.

		The dmi/tables provides raw SMBIOS entry point and DMI tables
		through sysfs as an alternative to utilities reading them
		from /dev/mem. The raw SMBIOS entry point and DMI table are
		presented as binary attributes and are accessible via:

		/sys/firmware/dmi/tables/smbios_entry_point
		/sys/firmware/dmi/tables/DMI

		The complete DMI information can be obtained using these two
		tables.
+2 −0
Original line number Original line Diff line number Diff line
@@ -3337,6 +3337,8 @@ F: drivers/hwmon/dme1737.c
DMI/SMBIOS SUPPORT
DMI/SMBIOS SUPPORT
M:	Jean Delvare <jdelvare@suse.de>
M:	Jean Delvare <jdelvare@suse.de>
S:	Maintained
S:	Maintained
T:	quilt http://jdelvare.nerim.net/devel/linux/jdelvare-dmi/
F:	Documentation/ABI/testing/sysfs-firmware-dmi-tables
F:	drivers/firmware/dmi-id.c
F:	drivers/firmware/dmi-id.c
F:	drivers/firmware/dmi_scan.c
F:	drivers/firmware/dmi_scan.c
F:	include/linux/dmi.h
F:	include/linux/dmi.h
+8 −9
Original line number Original line Diff line number Diff line
@@ -566,7 +566,6 @@ static struct kobj_type dmi_sysfs_entry_ktype = {
	.default_attrs = dmi_sysfs_entry_attrs,
	.default_attrs = dmi_sysfs_entry_attrs,
};
};


static struct kobject *dmi_kobj;
static struct kset *dmi_kset;
static struct kset *dmi_kset;


/* Global count of all instances seen.  Only for setup */
/* Global count of all instances seen.  Only for setup */
@@ -648,17 +647,20 @@ static void cleanup_entry_list(void)


static int __init dmi_sysfs_init(void)
static int __init dmi_sysfs_init(void)
{
{
	int error = -ENOMEM;
	int error;
	int val;
	int val;


	/* Set up our directory */
	if (!dmi_kobj) {
	dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
		pr_err("dmi-sysfs: dmi entry is absent.\n");
	if (!dmi_kobj)
		error = -ENODATA;
		goto err;
		goto err;
	}


	dmi_kset = kset_create_and_add("entries", NULL, dmi_kobj);
	dmi_kset = kset_create_and_add("entries", NULL, dmi_kobj);
	if (!dmi_kset)
	if (!dmi_kset) {
		error = -ENOMEM;
		goto err;
		goto err;
	}


	val = 0;
	val = 0;
	error = dmi_walk(dmi_sysfs_register_handle, &val);
	error = dmi_walk(dmi_sysfs_register_handle, &val);
@@ -675,7 +677,6 @@ static int __init dmi_sysfs_init(void)
err:
err:
	cleanup_entry_list();
	cleanup_entry_list();
	kset_unregister(dmi_kset);
	kset_unregister(dmi_kset);
	kobject_put(dmi_kobj);
	return error;
	return error;
}
}


@@ -685,8 +686,6 @@ static void __exit dmi_sysfs_exit(void)
	pr_debug("dmi-sysfs: unloading.\n");
	pr_debug("dmi-sysfs: unloading.\n");
	cleanup_entry_list();
	cleanup_entry_list();
	kset_unregister(dmi_kset);
	kset_unregister(dmi_kset);
	kobject_del(dmi_kobj);
	kobject_put(dmi_kobj);
}
}


module_init(dmi_sysfs_init);
module_init(dmi_sysfs_init);
+105 −18
Original line number Original line Diff line number Diff line
@@ -10,6 +10,9 @@
#include <asm/dmi.h>
#include <asm/dmi.h>
#include <asm/unaligned.h>
#include <asm/unaligned.h>


struct kobject *dmi_kobj;
EXPORT_SYMBOL_GPL(dmi_kobj);

/*
/*
 * DMI stands for "Desktop Management Interface".  It is part
 * DMI stands for "Desktop Management Interface".  It is part
 * of and an antecedent to, SMBIOS, which stands for System
 * of and an antecedent to, SMBIOS, which stands for System
@@ -20,6 +23,9 @@ static const char dmi_empty_string[] = " ";
static u32 dmi_ver __initdata;
static u32 dmi_ver __initdata;
static u32 dmi_len;
static u32 dmi_len;
static u16 dmi_num;
static u16 dmi_num;
static u8 smbios_entry_point[32];
static int smbios_entry_point_size;

/*
/*
 * Catch too early calls to dmi_check_system():
 * Catch too early calls to dmi_check_system():
 */
 */
@@ -80,7 +86,7 @@ static const char * __init dmi_string(const struct dmi_header *dm, u8 s)
 *	We have to be cautious here. We have seen BIOSes with DMI pointers
 *	We have to be cautious here. We have seen BIOSes with DMI pointers
 *	pointing to completely the wrong place for example
 *	pointing to completely the wrong place for example
 */
 */
static void dmi_table(u8 *buf,
static void dmi_decode_table(u8 *buf,
			     void (*decode)(const struct dmi_header *, void *),
			     void (*decode)(const struct dmi_header *, void *),
			     void *private_data)
			     void *private_data)
{
{
@@ -89,9 +95,9 @@ static void dmi_table(u8 *buf,


	/*
	/*
	 * Stop when we have seen all the items the table claimed to have
	 * Stop when we have seen all the items the table claimed to have
	 * (SMBIOS < 3.0 only) OR we reach an end-of-table marker OR we run
	 * (SMBIOS < 3.0 only) OR we reach an end-of-table marker (SMBIOS
	 * off the end of the table (should never happen but sometimes does
	 * >= 3.0 only) OR we run off the end of the table (should never
	 * on bogus implementations.)
	 * happen but sometimes does on bogus implementations.)
	 */
	 */
	while ((!dmi_num || i < dmi_num) &&
	while ((!dmi_num || i < dmi_num) &&
	       (data - buf + sizeof(struct dmi_header)) <= dmi_len) {
	       (data - buf + sizeof(struct dmi_header)) <= dmi_len) {
@@ -108,15 +114,24 @@ static void dmi_table(u8 *buf,
		if (data - buf < dmi_len - 1)
		if (data - buf < dmi_len - 1)
			decode(dm, private_data);
			decode(dm, private_data);


		data += 2;
		i++;

		/*
		/*
		 * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
		 * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
		 * For tables behind a 64-bit entry point, we have no item
		 * count and no exact table length, so stop on end-of-table
		 * marker. For tables behind a 32-bit entry point, we have
		 * seen OEM structures behind the end-of-table marker on
		 * some systems, so don't trust it.
		 */
		 */
		if (dm->type == DMI_ENTRY_END_OF_TABLE)
		if (!dmi_num && dm->type == DMI_ENTRY_END_OF_TABLE)
			break;
			break;

		data += 2;
		i++;
	}
	}

	/* Trim DMI table length if needed */
	if (dmi_len > data - buf)
		dmi_len = data - buf;
}
}


static phys_addr_t dmi_base;
static phys_addr_t dmi_base;
@@ -125,16 +140,17 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
		void *))
		void *))
{
{
	u8 *buf;
	u8 *buf;
	u32 orig_dmi_len = dmi_len;


	buf = dmi_early_remap(dmi_base, dmi_len);
	buf = dmi_early_remap(dmi_base, orig_dmi_len);
	if (buf == NULL)
	if (buf == NULL)
		return -1;
		return -1;


	dmi_table(buf, decode, NULL);
	dmi_decode_table(buf, decode, NULL);


	add_device_randomness(buf, dmi_len);
	add_device_randomness(buf, dmi_len);


	dmi_early_unmap(buf, dmi_len);
	dmi_early_unmap(buf, orig_dmi_len);
	return 0;
	return 0;
}
}


@@ -478,6 +494,8 @@ static int __init dmi_present(const u8 *buf)
	if (memcmp(buf, "_SM_", 4) == 0 &&
	if (memcmp(buf, "_SM_", 4) == 0 &&
	    buf[5] < 32 && dmi_checksum(buf, buf[5])) {
	    buf[5] < 32 && dmi_checksum(buf, buf[5])) {
		smbios_ver = get_unaligned_be16(buf + 6);
		smbios_ver = get_unaligned_be16(buf + 6);
		smbios_entry_point_size = buf[5];
		memcpy(smbios_entry_point, buf, smbios_entry_point_size);


		/* Some BIOS report weird SMBIOS version, fix that up */
		/* Some BIOS report weird SMBIOS version, fix that up */
		switch (smbios_ver) {
		switch (smbios_ver) {
@@ -512,6 +530,9 @@ static int __init dmi_present(const u8 *buf)
				pr_info("SMBIOS %d.%d present.\n",
				pr_info("SMBIOS %d.%d present.\n",
				       dmi_ver >> 8, dmi_ver & 0xFF);
				       dmi_ver >> 8, dmi_ver & 0xFF);
			} else {
			} else {
				smbios_entry_point_size = 15;
				memcpy(smbios_entry_point, buf,
				       smbios_entry_point_size);
				pr_info("Legacy DMI %d.%d present.\n",
				pr_info("Legacy DMI %d.%d present.\n",
				       dmi_ver >> 8, dmi_ver & 0xFF);
				       dmi_ver >> 8, dmi_ver & 0xFF);
			}
			}
@@ -533,11 +554,12 @@ static int __init dmi_smbios3_present(const u8 *buf)
{
{
	if (memcmp(buf, "_SM3_", 5) == 0 &&
	if (memcmp(buf, "_SM3_", 5) == 0 &&
	    buf[6] < 32 && dmi_checksum(buf, buf[6])) {
	    buf[6] < 32 && dmi_checksum(buf, buf[6])) {
		dmi_ver = get_unaligned_be32(buf + 6);
		dmi_ver = get_unaligned_be32(buf + 6) & 0xFFFFFF;
		dmi_ver &= 0xFFFFFF;
		dmi_num = 0;			/* No longer specified */
		dmi_num = 0;			/* No longer specified */
		dmi_len = get_unaligned_le32(buf + 12);
		dmi_len = get_unaligned_le32(buf + 12);
		dmi_base = get_unaligned_le64(buf + 16);
		dmi_base = get_unaligned_le64(buf + 16);
		smbios_entry_point_size = buf[6];
		memcpy(smbios_entry_point, buf, smbios_entry_point_size);


		if (dmi_walk_early(dmi_decode) == 0) {
		if (dmi_walk_early(dmi_decode) == 0) {
			pr_info("SMBIOS %d.%d.%d present.\n",
			pr_info("SMBIOS %d.%d.%d present.\n",
@@ -629,6 +651,71 @@ void __init dmi_scan_machine(void)
	dmi_initialized = 1;
	dmi_initialized = 1;
}
}


static ssize_t raw_table_read(struct file *file, struct kobject *kobj,
			      struct bin_attribute *attr, char *buf,
			      loff_t pos, size_t count)
{
	memcpy(buf, attr->private + pos, count);
	return count;
}

static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0);
static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0);

static int __init dmi_init(void)
{
	struct kobject *tables_kobj;
	u8 *dmi_table;
	int ret = -ENOMEM;

	if (!dmi_available) {
		ret = -ENODATA;
		goto err;
	}

	/*
	 * Set up dmi directory at /sys/firmware/dmi. This entry should stay
	 * even after farther error, as it can be used by other modules like
	 * dmi-sysfs.
	 */
	dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
	if (!dmi_kobj)
		goto err;

	tables_kobj = kobject_create_and_add("tables", dmi_kobj);
	if (!tables_kobj)
		goto err;

	dmi_table = dmi_remap(dmi_base, dmi_len);
	if (!dmi_table)
		goto err_tables;

	bin_attr_smbios_entry_point.size = smbios_entry_point_size;
	bin_attr_smbios_entry_point.private = smbios_entry_point;
	ret = sysfs_create_bin_file(tables_kobj, &bin_attr_smbios_entry_point);
	if (ret)
		goto err_unmap;

	bin_attr_DMI.size = dmi_len;
	bin_attr_DMI.private = dmi_table;
	ret = sysfs_create_bin_file(tables_kobj, &bin_attr_DMI);
	if (!ret)
		return 0;

	sysfs_remove_bin_file(tables_kobj,
			      &bin_attr_smbios_entry_point);
 err_unmap:
	dmi_unmap(dmi_table);
 err_tables:
	kobject_del(tables_kobj);
	kobject_put(tables_kobj);
 err:
	pr_err("dmi: Firmware registration failed.\n");

	return ret;
}
subsys_initcall(dmi_init);

/**
/**
 * dmi_set_dump_stack_arch_desc - set arch description for dump_stack()
 * dmi_set_dump_stack_arch_desc - set arch description for dump_stack()
 *
 *
@@ -897,7 +984,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *, void *),
	if (buf == NULL)
	if (buf == NULL)
		return -1;
		return -1;


	dmi_table(buf, decode, private_data);
	dmi_decode_table(buf, decode, private_data);


	dmi_unmap(buf);
	dmi_unmap(buf);
	return 0;
	return 0;
Loading