Merge branch 'dmi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging
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
This commit is contained in:
commit
f7b08217c7
6 changed files with 143 additions and 31 deletions
|
@ -1,4 +1,4 @@
|
|||
What: /sys/firmware/dmi/
|
||||
What: /sys/firmware/dmi/entries/
|
||||
Date: February 2011
|
||||
Contact: Mike Waychison <mikew@google.com>
|
||||
Description:
|
22
Documentation/ABI/testing/sysfs-firmware-dmi-tables
Normal file
22
Documentation/ABI/testing/sysfs-firmware-dmi-tables
Normal file
|
@ -0,0 +1,22 @@
|
|||
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.
|
|
@ -3337,6 +3337,8 @@ F: drivers/hwmon/dme1737.c
|
|||
DMI/SMBIOS SUPPORT
|
||||
M: Jean Delvare <jdelvare@suse.de>
|
||||
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_scan.c
|
||||
F: include/linux/dmi.h
|
||||
|
|
|
@ -566,7 +566,6 @@ static struct kobj_type dmi_sysfs_entry_ktype = {
|
|||
.default_attrs = dmi_sysfs_entry_attrs,
|
||||
};
|
||||
|
||||
static struct kobject *dmi_kobj;
|
||||
static struct kset *dmi_kset;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int error = -ENOMEM;
|
||||
int error;
|
||||
int val;
|
||||
|
||||
/* Set up our directory */
|
||||
dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
|
||||
if (!dmi_kobj)
|
||||
if (!dmi_kobj) {
|
||||
pr_err("dmi-sysfs: dmi entry is absent.\n");
|
||||
error = -ENODATA;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dmi_kset = kset_create_and_add("entries", NULL, dmi_kobj);
|
||||
if (!dmi_kset)
|
||||
if (!dmi_kset) {
|
||||
error = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
val = 0;
|
||||
error = dmi_walk(dmi_sysfs_register_handle, &val);
|
||||
|
@ -675,7 +677,6 @@ static int __init dmi_sysfs_init(void)
|
|||
err:
|
||||
cleanup_entry_list();
|
||||
kset_unregister(dmi_kset);
|
||||
kobject_put(dmi_kobj);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -685,8 +686,6 @@ static void __exit dmi_sysfs_exit(void)
|
|||
pr_debug("dmi-sysfs: unloading.\n");
|
||||
cleanup_entry_list();
|
||||
kset_unregister(dmi_kset);
|
||||
kobject_del(dmi_kobj);
|
||||
kobject_put(dmi_kobj);
|
||||
}
|
||||
|
||||
module_init(dmi_sysfs_init);
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
#include <asm/dmi.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
struct kobject *dmi_kobj;
|
||||
EXPORT_SYMBOL_GPL(dmi_kobj);
|
||||
|
||||
/*
|
||||
* DMI stands for "Desktop Management Interface". It is part
|
||||
* 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_len;
|
||||
static u16 dmi_num;
|
||||
static u8 smbios_entry_point[32];
|
||||
static int smbios_entry_point_size;
|
||||
|
||||
/*
|
||||
* Catch too early calls to dmi_check_system():
|
||||
*/
|
||||
|
@ -80,18 +86,18 @@ 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
|
||||
* pointing to completely the wrong place for example
|
||||
*/
|
||||
static void dmi_table(u8 *buf,
|
||||
void (*decode)(const struct dmi_header *, void *),
|
||||
void *private_data)
|
||||
static void dmi_decode_table(u8 *buf,
|
||||
void (*decode)(const struct dmi_header *, void *),
|
||||
void *private_data)
|
||||
{
|
||||
u8 *data = buf;
|
||||
int i = 0;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* off the end of the table (should never happen but sometimes does
|
||||
* on bogus implementations.)
|
||||
* (SMBIOS < 3.0 only) OR we reach an end-of-table marker (SMBIOS
|
||||
* >= 3.0 only) OR we run off the end of the table (should never
|
||||
* happen but sometimes does on bogus implementations.)
|
||||
*/
|
||||
while ((!dmi_num || i < dmi_num) &&
|
||||
(data - buf + sizeof(struct dmi_header)) <= dmi_len) {
|
||||
|
@ -108,15 +114,24 @@ static void dmi_table(u8 *buf,
|
|||
if (data - buf < dmi_len - 1)
|
||||
decode(dm, private_data);
|
||||
|
||||
/*
|
||||
* 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
|
||||
*/
|
||||
if (dm->type == DMI_ENTRY_END_OF_TABLE)
|
||||
break;
|
||||
|
||||
data += 2;
|
||||
i++;
|
||||
|
||||
/*
|
||||
* 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 (!dmi_num && dm->type == DMI_ENTRY_END_OF_TABLE)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Trim DMI table length if needed */
|
||||
if (dmi_len > data - buf)
|
||||
dmi_len = data - buf;
|
||||
}
|
||||
|
||||
static phys_addr_t dmi_base;
|
||||
|
@ -125,16 +140,17 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
|
|||
void *))
|
||||
{
|
||||
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)
|
||||
return -1;
|
||||
|
||||
dmi_table(buf, decode, NULL);
|
||||
dmi_decode_table(buf, decode, NULL);
|
||||
|
||||
add_device_randomness(buf, dmi_len);
|
||||
|
||||
dmi_early_unmap(buf, dmi_len);
|
||||
dmi_early_unmap(buf, orig_dmi_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -478,17 +494,19 @@ static int __init dmi_present(const u8 *buf)
|
|||
if (memcmp(buf, "_SM_", 4) == 0 &&
|
||||
buf[5] < 32 && dmi_checksum(buf, buf[5])) {
|
||||
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 */
|
||||
switch (smbios_ver) {
|
||||
case 0x021F:
|
||||
case 0x0221:
|
||||
pr_debug("SMBIOS version fixup(2.%d->2.%d)\n",
|
||||
pr_debug("SMBIOS version fixup (2.%d->2.%d)\n",
|
||||
smbios_ver & 0xFF, 3);
|
||||
smbios_ver = 0x0203;
|
||||
break;
|
||||
case 0x0233:
|
||||
pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 51, 6);
|
||||
pr_debug("SMBIOS version fixup (2.%d->2.%d)\n", 51, 6);
|
||||
smbios_ver = 0x0206;
|
||||
break;
|
||||
}
|
||||
|
@ -512,6 +530,9 @@ static int __init dmi_present(const u8 *buf)
|
|||
pr_info("SMBIOS %d.%d present.\n",
|
||||
dmi_ver >> 8, dmi_ver & 0xFF);
|
||||
} else {
|
||||
smbios_entry_point_size = 15;
|
||||
memcpy(smbios_entry_point, buf,
|
||||
smbios_entry_point_size);
|
||||
pr_info("Legacy DMI %d.%d present.\n",
|
||||
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 &&
|
||||
buf[6] < 32 && dmi_checksum(buf, buf[6])) {
|
||||
dmi_ver = get_unaligned_be32(buf + 6);
|
||||
dmi_ver &= 0xFFFFFF;
|
||||
dmi_ver = get_unaligned_be32(buf + 6) & 0xFFFFFF;
|
||||
dmi_num = 0; /* No longer specified */
|
||||
dmi_len = get_unaligned_le32(buf + 12);
|
||||
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) {
|
||||
pr_info("SMBIOS %d.%d.%d present.\n",
|
||||
|
@ -629,6 +651,71 @@ void __init dmi_scan_machine(void)
|
|||
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()
|
||||
*
|
||||
|
@ -897,7 +984,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *, void *),
|
|||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
dmi_table(buf, decode, private_data);
|
||||
dmi_decode_table(buf, decode, private_data);
|
||||
|
||||
dmi_unmap(buf);
|
||||
return 0;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define __DMI_H__
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
/* enum dmi_field is in mod_devicetable.h */
|
||||
|
@ -74,7 +75,7 @@ struct dmi_header {
|
|||
u8 type;
|
||||
u8 length;
|
||||
u16 handle;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct dmi_device {
|
||||
struct list_head list;
|
||||
|
@ -93,6 +94,7 @@ struct dmi_dev_onboard {
|
|||
int devfn;
|
||||
};
|
||||
|
||||
extern struct kobject *dmi_kobj;
|
||||
extern int dmi_check_system(const struct dmi_system_id *list);
|
||||
const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
|
||||
extern const char * dmi_get_system_info(int field);
|
||||
|
|
Loading…
Reference in a new issue