summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--AUTHORS6
-rw-r--r--CHANGELOG1614
-rw-r--r--Makefile32
-rw-r--r--NEWS193
-rw-r--r--README2
-rw-r--r--biosdecode.c67
-rw-r--r--config.h5
-rw-r--r--dmidecode.c3312
-rw-r--r--dmidecode.h23
-rw-r--r--dmioem.c1294
-rw-r--r--dmioem.h2
-rw-r--r--dmiopt.c39
-rw-r--r--dmiopt.h2
-rw-r--r--dmioutput.c137
-rw-r--r--dmioutput.h34
-rw-r--r--man/biosdecode.821
-rw-r--r--man/dmidecode.8157
-rw-r--r--man/ownership.816
-rw-r--r--man/vpddecode.839
-rw-r--r--types.h27
-rw-r--r--util.c141
-rw-r--r--util.h1
-rw-r--r--version.h2
24 files changed, 4081 insertions, 3090 deletions
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 731f4e5..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-biosdecode
-dmidecode
-ownership
-vpddecode
-*.o
diff --git a/AUTHORS b/AUTHORS
index 748b985..7065f72 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -21,6 +21,9 @@ Roy Franz <roy.franz@linaro.org>
Tyler Bell <tyler.bell@hp.com>
Xie XiuQi <xiexiuqi@huawei.com>
Petr Oros <poros@redhat.com>
+Prabhakar Pujeri <prabhakar.pujeri@dell.com>
+Erwan Velu <e.velu@criteo.com>
+Jerry Hoemann <jerry.hoemann@hpe.com>
MANY THANKS TO (IN CHRONOLOGICAL ORDER)
Werner Heuser
@@ -90,3 +93,6 @@ Andrey Matveyev
Stefan Tauner
Naga Chumbalkar
Jens Rosenboom
+Lianbo Jiang
+Tianjia Zhang
+Ivan Tkachenko
diff --git a/CHANGELOG b/CHANGELOG
deleted file mode 100644
index 6f9123d..0000000
--- a/CHANGELOG
+++ /dev/null
@@ -1,1614 +0,0 @@
-2015-09-03 Jean Delvare <jdelvare@suse.de>
-
- * version.h: Set version to 3.1.
-
-2017-05-23 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c, dmiopt.c: Add a new option to extract OEM strings, like
- we already have for many other strings.
- * dmidecode.8: Document the new option.
-
-2017-04-27 Jean Delvare <jdelvare@suse.de>
-
- Update to support SMBIOS specification version 3.1.1.
-
- * dmidecode.c: Add support for 3-digit versions.
- * dmidecode.c: Add new enumerated values for processors (DMI type 4).
-
-2017-04-27 Jean Delvare <jdelvare@suse.de>
-
- Update to support SMBIOS specification version 3.1.0.
-
- * dmidecode.c: Add support for extended BIOS ROM size (DMI type 0).
- * dmidecode.c: Add new enumerated values for chassis types
- (DMI type 3).
- * dmidecode.c: Add new enumerated values for processors (DMI type 4).
- * dmidecode.c: Don't assume 8-bit processor family in dmi_processor_id
- (DMI type 4).
- * dmidecode.c: Decode the MIDR register on ARM processors
- (DMI type 4).
- * dmidecode.c: Add support for large cache sizes (DMI type 7).
- * dmidecode.c: Add Mini PCIe system slot enumerated values
- (DMI type 9).
- * dmidecode.c: Clarify the memory speed unit (DMI type 17).
- * dmidecode.c: Add support for structure type 43 (TPM Device).
-
-2017-04-11 Jean Delvare <jdelvare@suse.de>
-
- * util.c: Don't leak a file descriptor in function read_file.
- * util.c, util.c, dmidecode.c: Let callers pass an offset to function
- read_file.
- * dmidecode.c: Fix reading from SMBIOS 3 dump files using a 64-bit
- entry point.
-
-2017-04-10 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Decode the processor ID of the Intel Core M, AMD
- Athlon X4 and AMD Opteron X1000/X2000 processors (DMI type 4).
- * dmidecode.c: Display the IPMI interrupt number as a decimal
- number (DMI type 38).
-
-2017-01-20 Jean Delvare <jdelvare@suse.de>
-
- * biosdecode.c: Decode the entry point defined in the Intel
- Multiprocessor specification.
-
-2017-01-20 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Only decode one DMI table.
- This fixes Savannah bug #50022:
- https://savannah.nongnu.org/bugs/?50022
-
-2016-09-22 Jean Delvare <jdelvare@suse.de>
-
- * README: Explain that we can no longer support Cygwin.
-
-2016-06-30 Petr Oros <poros@redhat.com>
-
- * dmidecode.c: Unmask LRDIMM in memory type detail (DMI type 17).
-
-2015-11-02 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c, util.c, util.h: Let read_file return the actual data
- size.
- * dmidecode.c: Use read_file to read the DMI table from sysfs.
- This fixes Savannah bug #46176:
- https://savannah.nongnu.org/bugs/?46176
- * dmidecode.c: Check the sysfs entry point length.
-
-2015-10-21 Xie XiuQi <xiexiuqi@huawei.com>
-
- * dmidecode.c: Handle SMBIOS 3.0 entry points on EFI systems.
-
-2015-10-20 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Handle OEM-specific types in group associations
- (DMI type 14).
-
-2015-10-14 Jean Delvare <jdelvare@suse.de>
-
- * util.c: Avoid SIGBUS on mmap failure.
- This fixes Savannah bug #46066:
- https://savannah.nongnu.org/bugs/?46066
- * util.c: Fix error paths in mem_chunk.
-
-2015-10-01 Roy Franz <roy.franz@linaro.org>
-
- * dmiopt.c: Add "--no-sysfs" option description to -h output.
-
-2015-09-03 Jean Delvare <jdelvare@suse.de>
-
- * version.h: Set version to 3.0.
-
-2015-08-04 Tyler Bell <tyler.bell@hp.com>
-
- * dmioem.c: Decode HP-specific DMI type 233
- * dmioem.c: Refactored HP-specific types 209 and 221 to use common code
- * dmioem.c: Documented spec for HP-specific types 209, 221 and 233
-
-2015-05-21 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Fix up invalid DMI type 34 structure length.
- * dmioem.c: Decode HP-specific DMI types 212 and 219.
- * dmioem.c: Move function is_printable to dmidecode.c.
-
-2015-05-13 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Add support for SMBIOS3 EFI table.
- * dmidecode.c: Fix warnings about comparison between signed and
- unsigned integers.
- * util.c: Fix warnings about unused labels when building without
- -DUSE_MMAP.
- * dmioem.c: Strip spaces at the end of vendor names.
- * dmioem.c: Decode Acer-specific DMI type 170.
-
-2015-05-12 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Remove extra blank line after hidden DMI type 40
- structure.
-
-2015-05-04 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Move table decoding to a separate function.
- * dmidecode.c: Simplify function dmi_table_dump.
- * dmidecode.c: Display types 41 and 42 in quiet mode too.
- * dmidecode.c: Get OEM vendor from System Information (DMI type 1).
-
-2015-04-28 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.h, dmiopt.h: Fix sparse errors.
- * biosdecode.c, dmiopt.c, ownership.c, vpdopt.c: Fix sparse warnings.
- * util.c: Fix sparse warning.
-
-2015-04-27 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Fix --dump-bin when reading from sysfs.
-
-2015-04-27 Jean Delvare <jdelvare@suse.de>
-
- Update to support SMBIOS specification version 3.0.0.
-
- * dmidecode.c: Add support for the new _SM3_ 64-bit entry point
- defined in the SMBIOS specification version 3.0.0, including
- support of 64-bit addresses and 32-bit table lengths.
- * dmidecode.c: Add 3 new chassis types (DMI type 3).
- * dmidecode.c: Add 4 new processor families (DMI type 4).
- * dmidecode.c: Add 4 new Intel socket types (DMI type 4).
- * dmidecode.c: Add 13 new slot types (DMI type 9).
- * dmidecode.c: Add 4 new memory device types (DMI type 17).
- * dmidecode.c: Add support for processors with more than 255 cores
- or threads (DMI type 4).
- * dmidecode.c: Stop decoding v3 tables at End-of-Table marker.
-
-2015-04-21 Roy Franz <roy.franz@linaro.org>
-
- * util.c, util.h: Add utility function read_file, which reads an
- entire binary file into a buffer.
- * dmidecode.c: Add passing of flags parameter to dmi_table.
- * dmidecode.c: Add reading of SMBIOS tables from sysfs.
- * dmidecode.c, dmiopt.c, dmiopt.h: Add --no-sysfs option to disable
- use of sysfs.
- * dmidecode.8: Document the changes above.
-
-2015-04-20 Jean Delvare <jdelvare@suse.de>
-
- * biosdecode.c: Add support for the _SM3_ entry point, as defined in
- the SMBIOS 3.0.0 specification.
-
-2014-11-14 Jean Delvare <jdelvare@suse.de>
-
- * man/dmidecode.8: Add a note about DMI strings available from sysfs
- on Linux.
-
-2014-10-13 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Add support for DDR4 (DMI type 17). Patch from Tomohiro
- Kimura. The value was taken from preliminary SMBIOS specification
- version 3.0.0d.
- This fixes Savannah bug #43370:
- https://savannah.nongnu.org/bugs/?43370
-
-2014-07-11 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Decode the CPUID of recent AMD processors (DMI type 4).
-
-2014-03-20 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Let legacy_decode be quiet in dump mode too.
- * dmidecode.c: Skip the SMBIOS version comparison in quiet mode.
- Patch from Jens Rosenboom.
-
-2014-02-25 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Fix spacing of memory module voltage attributes
- (DMI type 17).
-
-2014-01-13 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Decode ID of PCI Express 3 slots (DMI type 9).
- This fixes Savannah bug #40178:
- https://savannah.nongnu.org/bugs/?40178
-
-2014-01-13 Jean Delvare <jdelvare@suse.de>
-
- * LICENSE: Update to the latest upstream version. Amongst other
- things, this fixes the FSF address.
-
-2013-04-24 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Strip trailing zeroes from memory voltage values
- (DMI type 17).
- * dmidecode.c: Fix support for new processor upgrade types (DMI
- type 4) and new memory device type (DMI type 17.)
-
-2013-04-17 Anton Arapov <anton@redhat.com>
-
- * version.h: Set version to 2.12.
-
-2013-04-17 Anton Arapov <anton@redhat.com>
-
- Update to support SMBIOS specification version 2.8.0.
-
- * dmidecode.c: Correct processor family name (DMI type 4).
- * dmidecode.c: Correct typo in processor upgrade type (DMI type 4).
- * dmidecode.c: Add 9 new processor families (DMI type 4).
- * dmidecode.c: Add 2 new Intel socket types (DMI type 4).
- * dmidecode.c: Add Min/Max/Configured memory voltages (DMI type 17).
- * dmidecode.c: Add LRDIMM to memory device list (DMI type 17).
-
-2012-03-26 Anton Arapov <anton@redhat.com>
-
- * man/dmidecode.8: Add missing DMI type introduced with SMBIOS 2.7+, and
- include the information about the extra output when dmidecode is run
- on a hardware that has non-supported SMBIOS version.
-
-2012-03-12 Anton Arapov <anton@redhat.com>
-
- * dmioem.c: Add "PXE" to the HP OEM Type 209 output so it is similar to
- the "iSCSI" description in HP OEM Type 221. Patch from Naga Chumbalkar.
-
-2011-11-18 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Properly print the hexadecimal value of invalid
- string characters.
-
-2011-11-14 Anton Arapov <anton@redhat.com>
-
- * dmidecode.c: Make dmi_chassis_type aware of the lock bit.
- Patch from Stefan Tauner.
- * config.h: Haiku dropped the _BEOS_ definition in favor of its own
- platform identification _HAIKU_. Patch from Francois Revol.
-
-2011-04-20 Jean Delvare <jdelvare@suse.de>
-
- Update to support SMBIOS specification version 2.7.1.
-
- * dmidecode.c: Add 6 AMD processor families (DMI type 4).
- * dmidecode.c: Add cache associativity value
- "20-way Set-associative" (DMI type 7).
- * dmidecode.c: Add PCI Express 3 slot types (DMI type 9).
-
-2011-01-25 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Fix boundary checks of memory array location codes
- (DMI type 16). Reported by Andrey Matveyev.
-
-2011-01-19 Anton Arapov <anton@redhat.com>
-
- * version.h: Set version to 2.11.
-
-2010-11-24 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Assume that the max power capacity is expressed in
- Watts, not milliWatts (DMI type 39). The specification isn't
- clear about the actual unit, but the only implementation I've
- seen (HP Proliant G7) clearly uses Watts. Also, using milliWatts
- would limit the max value that can be stored to 32 W, which
- doesn't make much sense.
- * dmidecode.c: Fix offset of partition width (DMI type 19).
- * dmidecode.c: Decode BIOS language information flags
- (DMI type 13).
- * dmidecode.c: Fix CPU flags mask (DMI type 4).
- * dmidecode.c: Reword "PCI Express Gen 2" to just "PCI Express 2"
- (DMI type 9).
- * dmidecode.c: Decode the slot ID for all PCI Express and PCI
- Express 2 slots (DMI type 9).
-
-2010-11-24 Jean Delvare <jdelvare@suse.de>
-
- Update to support SMBIOS specification version 2.7.0.
-
- * dmidecode.c: Update all references to the SMBIOS specification
- to match the new numbering.
- * dmidecode.c: Add UEFI support and virtual machine flags to BIOS
- characteristics (DMI type 0).
- * dmideocde.c: Add SKU number field to system enclosure or chassis
- (DMI type 3).
- * dmidecode.c: Add many Intel, AMD and VIA CPU family names
- (DMI type 4).
- * dmidecode.c: Add many socket formats (DMI type 4).
- * dmidecode.c: Add processor characteristics flags (DMI type 4).
- * util.c, util.h: Add utility function u64_range, which computes
- the range between two u64 values.
- * dmidecode.c: Add support for memory arrays of 2 TB and more
- (DMI types 16, 19 and 20).
- * dmidecode.c: Add support for memory devices of 32 GB and more
- (DMI type 17).
- * dmidecode.c: Add description of cooling device (DMI type 27).
- * dmidecode.c: Add limited support for new DMI type 42 (Management
- Controller Host Interface).
-
-2010-11-16 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Handle ambiguous processor family value 0x30
- (DMI type 4).
- * dmidecode.c: Prevent unlikely array overrun when decoding
- processor family value 0xBE (DMI type 4).
- * dmidecode.c: Handle DMI type 2 record of size 0x0E.
-
-2010-11-11 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Fix decoding of IPMI base address LSB.
-
-2010-11-09 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Drop redundant/obsolete references to
- CIM_Processor.Family.
-
-2010-10-26 Jean Delvare <jdelvare@suse.de>
-
- Update to support Intel AP-485 (CPUID) revision 36 (was 32).
-
- * dmidecode.c: Update the link to the AP-485 document, the revision
- and the table number.
- * dmidecode.c: Update two CPU flag descriptions (FXSR and HTT).
- Drop CPU flag IA64.
- * dmidecode.c: Update the list of processors for which we decode the
- CPUID flags.
-
-2010-10-11 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: One more SMBIOS version fix-up case.
- * Makefile: Rework BSD make compatibility trick. The previous
- trick would break GNU make 3.82.
-
-2010-09-29 Anton Arapov <anton@redhat.com>
-
- * util.c: makes dmidecode fall back to regular reads if the mmap
- fails. Patch from Olof Johansson.
-
-2010-09-21 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Fix Xeon 7xxx entries in CPU name lookup table
- (DMI type 4). Patch from Paul Flo Williams.
-
-2009-08-28 Jarod Wilson <jarod@redhat.com>
-
- Update to support SMBIOS specification version 2.6.1.
-
- * dmidecode.c: Add processor types "Dual-Core Xeon 5200",
- "Dual-Core Xeon 7200", "Quad-Core Xeon 7300", "QuadCore Xeon 7400",
- "Multi-Core Xeon 7400", "Core i7", "Dual-Core Celeron",
- "Multi-Core Xeon", "Dual-Core Xeon 3xxx", "Quad-Core Xeon 3xxx",
- "Dual-Core Xeon 5xxx", "Quad-Core Xeon 5xxx", "Dual-Core Xeon 7xxx",
- "Quad-Core Xeon 7xxx" and "Multi-Core Xeon 7xxx" (DMI type 4).
- * dmidecode.c: Add slot types "PCI Express Gen 2 x1",
- "PCI Express Gen 2 x2", "PCI Express Gen 2 x4",
- "PCI Express Gen 2 x8" and "PCI Express Gen 2 x16" (DMI type 9).
- * dmidecode.c: Add memory device types "DDR3" and "FB-DIMM"
- (DMI type 17).
- * dmidecode.c: Add cache associativity types "12-way Set-associative",
- "24-way Set-associative", "32-way Set-associative",
- "48-way Set-associative" and "64-way Set-associative" (DMI type 7).
-
-2009-07-27 Jean Delvare <jdelvare@suse.de>
-
- * dmioem.c: Recognize "Hewlett-Packard" as a possible DMI vendor
- string for HP. Orginal patch from Thomas Hiller (HP).
- * dmidecode.c: Add processor upgrade type "Socket LGA1366"
- (DMI type 4).
-
-2009-06-19 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Fix decoding of memory array capacity. A maximum
- capacity of 128 GB would erroneously be reported as Unknown,
- while a unknown capacity would be erroneously reported as 2048
- GB. Bug reported by Lin Li (HP).
-
-2009-04-30 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Warn if decoding an SMBIOS implementation which is
- newer than what we support.
-
-2009-04-04 Jean Delvare <jdelvare@suse.de>
-
- * Makefile: Clarify license.
-
-2008-11-23 Jean Delvare <jdelvare@suse.de>
-
- * biosdecode.c: Stop using the inline keyword. It causes more
- portability issues than is worth given how little we care about
- performance in this tool, and recent versions of gcc know when
- to inline functions anyway.
- * version.h: Set version to 2.10.
-
-2008-11-14 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Handle chassis information records of size 19
- (DMI type 3).
-
-2008-11-10 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Claim to support revision 32 of Intel AP-485
- (CPUID). No relevant change since revision 31.
- * dmidecode.c: Update reference to AMD CPUID document.
-
-2008-11-09 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Decode the CPUID of more Intel, VIA and AMD
- processors (DMI type 4).
- * dmidecode.c: More CPUID exceptions based on the version string
- (DMI type 4).
- * README: Drop reference to the Linux kernel.
- * README: Drop "model-specific issues" common problem entry, it is
- no longer relevant.
- * README: Simplify "IA-64" common problem entry, most of the
- issues are solved by now.
-
-2008-11-08 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Add many processor types taken from the CIM Schema.
- * dmidecode.c: Drop all references to the DMTF Master MIF
- document. This document hasn't been updated in years, so the
- additions it may contain are no longer relevant.
-
-2008-11-07 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Handle base board information records of size 9
- (DMI type 2).
- * dmidecode.c: Don't display access time equivalent of memory
- device speed (DMI type 17). The access time didn't add much
- value, and rounding effects made it look bad at times.
-
-2008-11-07 Jean Delvare <jdelvare@suse.de>
-
- Update to support SMBIOS specification version 2.6, fourth round.
-
- * dmidecode.c: Initial support for additional information entries
- (DMI type 40). Proper support of this new entry type would
- require redesigning a large part of the code, so I am waiting
- to see actual implementations of it to decide whether it's worth
- the effort.
- * dmidecode.c, dmidecode.8: Update reference SMBIOS document.
- * dmiopt.c, dmidecode.8: Include entry type 41 in --type baseboard.
-
-2008-11-05 Jean Delvare <jdelvare@suse.de>
-
- Update to support SMBIOS specification version 2.6, third round.
-
- * dmidecode.c: Decode the group number, bus number and
- device/function number of system slots (DMI type 9).
- Based on a preliminary patch by Matt Domsch.
- * dmidecode.c: Decode onboard devices extended information
- entries (DMI type 41). Based on a preliminary patch by Matt
- Domsch.
- * dmidecode.c: Add slot types "PCI Express x1", "PCI Express x2",
- "PCI Express x4", "PCI Express x8" and "PCI Express x16"
- (DMI type 9).
- * dmidecode.c: Decode the memory device rank (DMI type 17).
-
-2008-11-02 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Use binary search for dmi_processor_family, it's
- faster than linear search (DMI type 4).
- * dmidecode.c: Decode boot integrity services entry point entries
- (DMI type 31).
-
-2008-10-31 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: The compiler knows how to reuse strings, it doesn't
- need our help, and actually it does a better job without it. So,
- turn out_of_spec into a define.
- * dmidecode.c: Optimize functions dmi_processor_status(),
- dmi_cache_location(), dmi_system_reset_boot_option() and
- dmi_ipmi_register_spacing().
-
-2008-10-30 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c, dmiopt.c, dmidecode.8: Option --dump is only a
- modifier as --quiet is, so it's not actually mutually exclusive
- with the output format options.
- * dmidecode.c: Make options --dump-bin and --quiet work together.
- * dmidecode.c: Delay string filtering when option --dump is used.
- * dmidecode.c: Refactor dmi_processor_family function to avoid
- code duplication.
- * dmidecode.c: Fix up invalid SMBIOS version 2.51.
-
-2008-10-29 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Handle special case of processor family code 0xBE,
- which can be both Core 2 or K7. We use the processor
- manufacturer string as a hint (DMI type 4).
-
-2008-10-28 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c, dmidecode.h, dmiopt.c, dmiopt.h: Don't use function
- pointers for special string cases. Each special case is itself
- special and needs to call a function with its own prototype, so
- better have dedicated code to handle it all.
- * dmidecode.c, dmidecode.h, dmioem.c, dmioem.h: Mark a few
- pointers const.
- * dmidecode.c, util.c, util.h: When dumping the DMI table to a
- binary file, truncate the file first.
- * dmidecode.c: Support Processor Family 2 field also when queried
- with option --string.
-
-2008-10-27 Jean Delvare <jdelvare@suse.de>
-
- Update to support SMBIOS specification version 2.6, second round.
-
- * dmidecode.c: Add support for Processor Family 2 field
- (DMI type 4).
- * dmidecode.c: Add processor types "Turion 64 X2", "Core Solo",
- "Core 2 Duo", "ESA/390 G6", "z/Architectur", "C7-M", "C7-D",
- "C7" and "Eden" (DMI type 4).
- * dmidecode.c: Fix typo in processor type "AMD29000" (DMI type 4).
- * dmidecode.c: Add processor upgrade types "Socket S1",
- "Socket AM2" and "Socket F (1207)" (DMI type 4).
-
-2008-10-26 Jean Delvare <jdelvare@suse.de>
-
- Update to support SMBIOS specification version 2.6, first round.
-
- * dmidecode.c: Byte-swap the first 3 fields of the UUID
- (DMI type 1).
- * dmidecode.c: Add chassis types "Blade" and "Blade Enclosure"
- (DMI type 3).
-
-2008-10-26 Jean Delvare <jdelvare@suse.de>
-
- * dmiopt.c, dmidecode.8: Simplify the handling and documentation
- of mutually exclusive output format options.
- * dmidecode.8: Document the binary dump file format.
- * dmidecode.c: Don't display the source dump file name in quiet
- mode.
- * biosdecode.c, dmidecode.c, dmioem.c, dmiopt.c, dmiopt.h,
- ownership.c, types.h, util.c, vpddecode.c, vpdopt.c, vpdopt.h:
- Mass coding-style change: add spaces around operators.
- * vpddecode.c: Fix --quiet option.
- * dmidecode.h, dmiopt.h: Pass version information to print
- callback functions.
- * dmidecode.c: Fix up invalid SMBIOS version.
- * dmidecode.c: Handle base board information records of size 10
- (DMI type 2).
-
-2008-10-25 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Limit indentation in smbios_decode and
- legacy_decode.
- * dmidecode.c, dmiopt.c: Write binary dump to a compact file
- rather than a sparse file.
- * dmidecode.c, dmiopt.c, dmiopt.h: New option --from-dump, read
- the DMI data from a binary file.
- * dmidecode.8: Update the option --dump-bin, document the new
- option --from-dump.
-
-2008-08-28 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Add missing colon to temperature probe label.
- Patch from Alex Iribarren.
-
-2008-02-16 Jean Delvare <jdelvare@suse.de>
-
- * util.c, util.h: New helper function write_dump.
- * dmidecode.c, dmiopt.c, dmiopt.h: New option --dump-bin, dump
- the DMI data to a sparse binary file.
- * dmidecode.8: Document the new option --dump-bin.
- * Makefile, biosdecode.c, dmidecode.c, dmidecode.h, dmioem.c,
- dmioem.h, dmiopt.c, dmiopt.h, ownership.c, util.c, util.h,
- vpddecode.c, vpdopt.c, vpdopt.h: Update copyright statements.
- * dmidecode.c: Adjust the error message which is displayed when
- the table is unreachable.
-
-2007-06-30 Jean Delvare <jdelvare@suse.de>
-
- * config.h: Add support for Solaris (x86 only, of course). Based
- on a patch by Sun's Dan Mick, brought to my knowledge by
- Attila Nagy.
-
-2007-06-27 Jean Delvare <jdelvare@suse.de>
-
- * Makefile: Fix the uninstall-man target.
-
-2007-06-07 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: If the SMBIOS entry point decoding fails (for
- example due to a bad checksum), still try decoding the
- encapsulated DMI entry point. Suggested by Luke Suchocki.
- * dmidecode.c: Replace all occurrences of "KB" by the more
- correct "kB".
-
-2007-03-16 Jean Delvare <jdelvare@suse.de>
-
- * vpddecode.c: Stop asking the user to report bad checksums,
- unaligned records and the like. Such machines exist, too bad,
- we have to live with it.
-
-2007-02-27 Jean Delvare <jdelvare@suse.de>
-
- * biosdecode.c: Fix a compilation error with non-C99 compilers.
- Patch from Francois Revol.
-
-2007-02-26 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Fix an array overrun while decoding the system
- event log status (DMI type 15).
- * biosdecode.c: Use printf instead of fwrite.
- * dmidecode.8: Some OEM-specific types can be decoded now.
- * biosdecode.8: List the FJKEYINF entry point type.
- * vpddecode.8: The product name is no longer displayed.
- * version.h: Set version to 2.9.
-
-2007-02-16 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Do not print the BIOS base address and runtime size
- if the base address is 0. This happens on IA-64 because there's
- no BIOS.
- * Makefile, README: Do not build biosdecode, ownership and
- vpddecode on IA-64, as IA-64 systems have no BIOS. This was
- quite tricky to keep both GNU make and BSD make happy, but it
- seems that I finally succeeded.
-
-2007-02-13 Jean Delvare <jdelvare@suse.de>
-
- Update to support SMBIOS specification version 2.5, second round.
-
- * dmidecode.c: Decode new processor characteristics (multi-core,
- multi-thread, 64-bit) (DMI type 4).
- * dmidecode.c: Decode slot ID of AGP 8x and PCI Express slots (DMI
- type 9).
-
- * dmidecode.c: Fix the mask of 3 bitfield tests. This will let
- the memory type of some systems be properly reported as SDRAM.
- * dmidecode.c: Fix the AMD processors signature decoding.
- * README: Minor edits.
-
-2007-02-12 Jens Elkner <elkner@linofee.org>
-
- Update to support SMBIOS specification version 2.5, first round.
-
- * dmidecode.c: Add chassis types "CompactPCI" and "AdvancedTCA"
- (DMI type 3).
- * dmidecode.c: Add processor types "Turion 64",
- "Dual-Core Opteron", "Athlon 64 X2", "Celeron D", "Pentium D"
- and "Pentium EE" (DMI type 4).
- * dmidecode.c: Add processor upgrade types "Socket mPGA604",
- "Socket LGA771" and "Socket LGA775" (DMI type 4).
- * dmidecode.c: Add connector type "SAS/SATA Plug Receptacle" and
- port types "SATA" and "SAS" (DMI type 8).
- * dmidecode.c: Add on-board device types "PATA Controller",
- "SATA Controller" and "SAS Controller" (DMI type 10).
- * dmidecode.c: Add memory device form factor "FB-DIMM" and memory
- device type "DDR2 FB-DIMM" (DMI type 17).
-
-2007-02-12 Jean Delvare <jdelvare@suse.de>
-
- * dmioem.c: Share the code between HP-specific types 209 and 221.
- Both types are really the same, only the title is different.
- * dmioem.c: Make the HP-specific types 209 and 221 output a bit
- more verbose.
- * dmidecode.c: Let --type decode OEM-specific entries when
- possible.
- * dmidecode.c: Include decoded OEM-specific entries in quiet mode
- output (--quiet).
- * dmidecode.c: Do not complain about truncated entries in quiet
- mode.
- * dmioem.c: Decode HP-specific type 204 entries in a safer way:
- check the length before decoding, and don't assume that all
- strings are provided in the same order as they are used.
-
- Update to support Intel AP-485 (CPUID) revision 31 (was 28).
-
- * dmidecode.c: New CPUID flag IA64.
- * dmidecode.c: Fix the decoding of Intel extended family.
-
-2007-02-11 Jean Delvare <jdelvare@suse.de>
-
- * dmioem.c, dmioem.h: New.
- * Makefile, dmidecode.c, dmidecode.h, dmioem.c, dmioem.h: Move the
- decoding of OEM-specific entries to a separate source file.
- * dmidecode.c: DMI type 38 is tested by now.
- * dmioem.c: The PCI function is typically represented as a single
- digit.
- * Makefile, dmiopt.c, vpdopt.c, util.h: Define an ARRAY_SIZE macro
- which computes the size of a static array, and use it where
- relevant.
-
-2007-02-11 John Cagle <jcagle@kernel.org>
-
- * dmidecode.c: Add support for 3 HP-specific entries: system/rack
- locator (type 204), NIC MAC information (type 209) and NIC iSCSI
- MAC information (type 221).
-
-2007-01-14 Jean Delvare <jdelvare@suse.de>
-
- * vpddecode.c: Fix a rare warning.
- * biosdecode.c: Add support for the FJKEYINF entry point, which
- contains data related to the "application panel" on Fujitsu
- laptops.
-
-2006-05-23 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Fix a recently introduced compilation error with
- non-C99 compilers.
- * dmidecode.c: Check for short entries (less than 4 bytes), stop
- with an error when one is encountered.
-
-2006-05-13 Jean Delvare <jdelvare@suse.de>
-
- * vpddecode.c, README: Drop the product name lookup table. It
- was reported to be unreliable too many times, and was also
- difficult to maintain.
-
-2006-05-10 Jean Delvare <jdelvare@suse.de>
-
- * dmidecode.c: Don't cast from u8* to dmi_header*, else
- architectures which do not support unaligned memory accesses
- may break. Instead, copy the members individually. That's a
- bit slower, but that's also safer and we only need to do it
- once per DMI entry, so it's not time critical. So far, we
- were using a trick to later work around the unaligned memory
- access, but the compiler would still warn about the risk,
- which is always confusing.
- * config.h, types.h, README: Automatically enable the unaligned
- memory access workaround on ia64.
- * types.h: Inline U64. It makes sense per se and also lets us
- get rid of a warning about U64 being unused.
- * dmidecode.c: Detect EFI at run-time rather than compilation-
- time. Based on an original patch from Matthew Garrett. This
- will make x86 binaries work for both PC systems with BIOS and
- Macintosh systems with EFI. Also prevent a possible, though
- unlikely, NULL-pointer dereference in the EFI code.
-
-2006-02-25 Jean Delvare
-
- * dmidecode.c: Fix typo reported by David Wilson (DMI case 3).
-
-2006-02-04 Jean Delvare
-
- * vpddecode.c: Update lookup table from revision 2006-01-31 of IBM
- reference document (add product ID "7B").
- * version.h: Set version to 2.8.
-
-2006-01-21 Jean Delvare
-
- * vpddecode.c: The mysterious last character of xSeries records
- may be a BIOS revision. Display it as such when present and
- non zero, and ask users to report.
- * vpddecode.c: Adjust an error message.
- * dmidecode.8: Update the sample entry to match the new output
- format.
- * README: Improve the IA-64 specific section and the vpddecode
- tool description.
- * vpdopt.h: Add missing system header file include.
-
-2006-01-20 Jean Delvare
-
- * vpddecode.c: Assume a constant length of 12 characters for the
- "Default Flash Image File Name" entry. The 13th character never
- contained anything useful, so it probably has a different
- meaning (unknown for now).
-
-2005-12-24 Jean Delvare
-
- * vpddecode.c: Scan for VPD records on 4-byte boundaries instead
- of 16-byte boundaries. This is needed for some eServer xSeries
- 206. Still emit a warning if a VPD record is found not on a
- 16-byte boundary.
-
-2005-10-26 Jean Delvare
-
- * vpddecode.c: Add product ID "NR". Reported by Klaus Muth.
- * vpddecode.c: Update lookup table from revision 2005-10-06 of IBM
- reference document (add product IDs "77" and "78").
-
-2005-10-05 Jean Delvare
-
- Update to support IPMI specification version 2.0 (was 1.5).
-
- * dmidecode.c: Support IPMI interface type SSIF. Original patch
- by Garry Belka.
-
-2005-10-04 Jean Delvare
-
- * vpdopt.c: Display the list of all valid string keywords when
- --string is used without an argument.
- * vpddecode.8: Document the new -s, --string option.
- * dmidecode.8: List the four new string keywords.
- * vpddecode.c: Keep quiet when --string is used, even when no VPD
- record is found.
-
-2005-10-03 Jean Delvare
-
- * biosdecode.c: Fix a potential (but highly improbable) buffer
- overrun in the VPD record decoding.
- * biosdecode.c: Change the xSeries checksumming method to
- accommodate a strange xSeries 440 VPD record, as was done in
- vpddecode.c some weeks ago. Do not display the default flash
- image file name anymore, it's not so useful and the field length
- is now uncertain.
- * vpdopt.c, vpdopt.h: New.
- * Makefile, vpddecode.c, vpdopt.c, vpdopt.h: Move the command line
- handling of vpddecode to a separate source file.
- * vpddecode.c, vpdopt.c, vpdopt.h: Add option -s, --string. It
- prints one selected VPD string instead of the regular output.
-
-2005-09-24 Jean Delvare
-
- * dmiopt.c: Fix incorrect header include. The strcasecmp function
- is defined in <strings.h>, not <string.h>. Reported by Petter
- Reinholdtsen.
-
-2005-09-14 Jean Delvare
-
- * dmidecode.h: New.
- * dmidecode.c, dmidecode.h, Makefile: Export four specific
- decoding functions, make them suitable for external call.
- * dmidecode.c, dmiopt.c, dmiopt.h, Makefile: Make it possible
- for --string to print decoded binary data rather than only
- DMI strings. Add four such string keywords.
- * dmidecode.c, dmiopt.c, dmiopt.h: Modify the opt structure
- to handle the string option more efficiently.
-
-2005-09-13 Jean Delvare
-
- * vpddecode.c: Slightly change the xSeries checksumming method to
- accommodate a strange xSeries 440 VPD record. Also tweak the
- decoding of the "Default Flash Image File Name" entry. Thanks
- to Torsten Seemann for providing a test VPD record.
-
-2005-09-05 Jean Delvare
-
- * Makefile: Use -Wundef.
-
-2005-08-31 Jean Delvare
-
- * dmidecode.c: Drop trailing dot from handle description line.
-
-2005-08-29 Jean Delvare
-
- * dmidecode.c: Reword a comment about CPUID.
- * dmidecode.c: Claim to support revision 28 of Intel AP-485
- (CPUID). No relevant change since revision 27.
-
-2005-08-25 Jean Delvare
-
- * vpddecode.c: Add product ID "VI". Reported by Torsten Seemann.
- * vpddecode.c: Update lookup table from revision 2005-06-24 of IBM
- reference document (add product IDs "1U", "1X", "70", "74", "75"
- and "76", update product ID "1Y").
- * dmiopt.c: Complain about unknown options again.
- * biosdecode.c, ownership.c, vpddecode.c: getopt_long() will never
- return ':'.
-
-2005-08-04 Jean Delvare
-
- * README: Manual pages document the command line interface.
- A discussion list exists for developers. Mmap is used on
- most systems, not just Linux.
- * version.h: Set version to 2.7.
-
-2005-08-02 Jean Delvare
-
- * dmiopt.c, dmidecode.8: Options --dump and --quiet are mutually
- exclusive.
-
-2005-06-23 Jean Delvare
-
- * dmiopt.c, dmidecode.8: Options --dump and --string are mutually
- exclusive.
-
-2005-06-22 Jean Delvare
-
- * dmiopt.c: Display the list of all valid type or string keywords
- when --type or --string, respectively, is used without an
- argument or with an invalid one.
- * dmidecode.8: Document the new -s, --string option. Update the
- -t, --type option documentation.
- * dmiopt.c, dmidecode.8: Add string keyword "bios-release-date",
- the Linux kernel uses it.
- * dmidecode.c, dmidecode.8: Fix typo ("Controler" becomes
- "Controller").
-
-2005-06-21 Jean Delvare
-
- * dmidecode.c, dmiopt.c, dmiopt.h: Add option -s, --string. It
- prints one selected DMI string instead of the regular output.
-
-2005-06-18 Jean Delvare
-
- * dmidecode.c: Hide handle references and entries of unknown
- type when --quiet is used.
- * dmidecode.8: Document the new -q, --quiet option.
- * dmidecode.c: Stop decoding at end of table entry when --quiet
- is used. Also don't warn about incorrect table length or entries
- count when --quiet is used.
-
-2005-06-17 Jean Delvare
-
- * dmidecode.c, dmiopt.c, dmiopt.h: Add option -q, --quiet. It
- makes the output less verbose.
- * dmidecode.c: Suppress one level of indentation in the output,
- insert blank lines between records. This will hopefully make
- the output easier to read.
- * dmidecode.c: Hide table address and size when --type is used.
-
-2005-06-16 Jean Delvare
-
- * dmidecode.8: Document the new -t, --type option.
-
-2005-06-15 Jean Delvare
-
- * dmiopt.c, dmiopt.h: New.
- * Makefile, dmidecode.c, dmiopt.c, dmiopt.h: Move the command line
- handling of dmidecode to a separate source file.
- * dmiopt.c: Define keywords to be used with --type (instead of
- numeric values).
-
-2005-06-14 Jean Delvare
-
- * dmidecode.c: Centralize the main exit point. This allows fixing
- a minor, recently introduced memory leak which was happening on
- error conditions.
-
-2005-06-13 Jean Delvare
-
- * dmidecode.c: Add option -t, --type. It limits the output to
- the given type(s) of DMI entries.
-
-2005-05-25 Jean Delvare
-
- * vpddecode.c: Add product IDs "KE", "NT" and "ZR". Reported by
- Bernd Krumboeck.
-
-2005-05-15 Jean Delvare
-
- * dmidecode.8, vpddecode.8: Document the new -u, --dump option.
-
- Update to support SMBIOS specification version 2.4 (was 2.4
- preliminary). There is actually no difference between 2.4
- preliminary and 2.4 final.
-
- * dmidecode.c: Update the "System Management BIOS Reference
- Specification" version.
-
-2005-04-26 Jean Delvare
-
- * vpddecode.c: Add product ID "M1". Reported by Myke Olson.
- * vpddecode.c: Add option -u, --dump. It disables decoding of the
- VPD records, a raw dump is displayed instead. This option is
- mainly intended for debugging.
-
-2005-04-03 Jean Delvare
-
- * Makefile: Use variables for install and rm commands, so that these
- can be overridden by the caller.
-
-2005-03-25 Jean Delvare
-
- * Makefile: Install some documentation files (README, CHANGELOG,
- AUTHORS).
-
- Update to support SMBIOS specification version 2.4 preliminary
- [11/18/2004] (was 2.3.4).
-
- * dmidecode.c: Add BIOS characteristics (DMI type 0).
- * dmidecode.c: Display BIOS and firmware revisions where available
- (DMI type 0).
- * dmidecode.c: Display system SKU number and family where available
- (DMI type 1).
- * dmidecode.c: Add system slot types and widths (DMI type 9).
- * dmidecode.c: Add memory device type "DDR2" (DMI type 17).
-
-2005-03-20 Jean Delvare
-
- * Makefile: Install manual pages under $(prefix)/share/man by
- default, instead of $(prefix)/man, so as to comply with the FHS.
-
-2005-03-08 Jean Delvare
-
- * vpddecode.c: Update lookup table from revision 2005-03-08 of IBM
- reference document (add product ID "1V", update product ID "1R").
- Thanks to Ingo van Lil for reporting about product ID "1V".
-
-2005-03-06 Jean Delvare
-
- * dmidecode.c: Add option -u, --dump. It disables decoding of the
- entries, raw dumps are displayed instead. This option is mainly
- intended for debugging.
- * Makefile: Use -Winline.
- * dmidecode.c: Make ASCII filtering of strings faster.
-
-2005-02-28 Jean Delvare
-
- * version.h: Set version to 2.6.
- * Makefile: ownership.o depends on version.h.
-
-2005-02-24 Jean Delvare
-
- * vpddecode.c: Add product ID "2C". Reported by Tomek Mateja.
-
-2005-02-17 Jean Delvare
-
- * vpddecode.c: Add product IDs "OP" and "PN". Reported by Scott
- Denham.
- * vpddecode.c: Fix typo in one product name (560E improperly
- spelled 650E).
- * vpddecode.c: Add product IDs "IW" and "IY", as added recently
- on IBM's reference web page. Update reference.
- * config.h: Use mmap on all but BeOS, instead of only Linux.
-
-2005-02-12 Jean Delvare
-
- * util.c: Fix incorrect length in munmap call.
- * Makefile: Use -Wmissing-prototypes.
- * dmidecode.c: Fix maximum battery error value.
-
-2005-02-11 Jean Delvare
-
- * Makefile: Discard -pedantic, we don't really need this.
- * util.c: Display an error message on memory shortage. Suggested
- by Don Howard.
-
- Fix a bug causing dmidecode to crash on some systems with more than
- 2 GB of memory. This is a signed vs unsigned issue, which existed
- up to version 2.2, was fixed in 2.3 but reintroduced in a different
- form in 2.5 as part of a code clean up and refactoring.
- https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=112355
- Thanks to Petter Reinholdtsen for reporting. Thanks to Don Howard
- for additional insight.
-
- * dmidecode.c, util.c, util.h: Use size_t instead of off_t when
- handling memory addresses.
-
-2005-02-10 Jean Delvare
-
- * dmidecode.c: Add option -h, --help, display a usage summary.
- * biosdecode.c, ownership.c, vpddecode.c: Copy command-line handling
- from dmidecode.c.
- * biosdecode.8, dmidecode.8, ownership.8, vpddecode.8: Document
- the new command-line interface.
-
-2005-02-06 Jean Delvare
-
- * Makefile: Everything depends on config.h.
- * dmidecode.c: Add basic command-line handling. This was suggested
- a long time ago by Erwan Velu.
-
-2005-02-01 Jean Delvare
-
- * vpddecode.c: Add product IDs "AP", "KP" and "RD". Reported by
- David Rosala.
-
-2005-01-17 Jean Delvare
-
- * README: Add a note about Cygwin. Thanks to Dominik Klein for
- reporting success.
-
-2004-12-10 Jean Delvare
-
- Increase portability and configurability to in order to support BeOS.
-
- * config.h: New.
- * config.h: Define a default memory device.
- * biosdecode.c, dmidecode.c, ownership.c, vpddecide.c: Include
- config.h and use the defined default memory device.
- * Makefile, config.h, util.c, README: Move USE_MMAP to config.h,
- use mmap on Linux only.
-
-2004-11-22 Jean Delvare
-
- * biosdecode.c: Avoid size_t in printf. Should remove a warning on
- ia64. Thanks to Petter Reinholdtsen for reporting.
- * util.c: Use sysconf(_SC_PAGESIZE) instead of getpagesize() where
- available. This may remove a warning on ia64 as a side effect.
- Thanks to Petter Reinholdtsen for reporting.
-
-2004-11-21 Jean Delvare
-
- * util.c, util.h: Function myread has no more user outside of util.c.
- * biosdecode.c: Speed improvements.
-
-2004-11-20 Jean Delvare
-
- * biosdecode.c, ownership.c, vpddecode.c: Make use of the mem_chunk
- function.
- * vpddecode.c: Simplify the memory loop code a bit.
-
-2004-11-12 Jean Delvare
-
- * dmidecode.c: Hide bank connection type for non-installed memory
- modules.
- * dmidecode.c: Reference comment fix.
- * dmidecode.c: Hide watchdog timer details when no watchdog is
- present. Change label for no watchdog.
- * README: Match case change for PREFIX (now prefix) in the Makefile
- file. Reported by Raul Nunez de Arenas Coronado.
-
-2004-11-12 Jean Delvare
-
- Update to support DMTF Master MIF version 040707 (was 030621).
-
- * dmidecode.c: One additional processor type (Sempron).
- * dmidecode.c: One additional processor type (Efficeon TM8800).
- * dmidecode.c: One additional processor upgrade type (Socket 939).
- * dmidecode.c: Add the AMD Sempron to the list of x86-class
- processors.
-
- Update to support Intel AP-485 (CPUID) revision 27 (was 25).
-
- * dmidecode.c: Rename SBF flag to PBE.
-
-2004-11-11 Jean Delvare
-
- * util.c: More helpful error messages.
- * util.c: Use MAP_SHARED instead of MAP_PRIVATE in mmap.
- * version.h: Set version to 2.5.
-
-2004-11-10 Jean Delvare
-
- * README: Update dmidecode presentation (copied from the web page).
- Move the list of supported systems from the documentation section
- to the installation section.
-
-2004-11-09 Jean Delvare
-
- * vpddecode.c: Update product ID "1R". Reported by Marco Wertejuk.
-
-2004-10-24 Jean Delvare
-
- * util.c: Workaround missing MAP_FAILED definition, needed on
- old systems. Original patch from Durval Menezes.
-
-2004-10-14 Jean Delvare
-
- * dmidecode.c: Search for EFI systab at /sys/firmware/efi/systab.
- Original patch from Alex Williamson.
- * dmidecode.c: Remove warning about legacy_decode not being used
- when USE_EFI is defined.
- * dmidecode.c: Detect missing SMBIOS entry point in efi/systab.
- * dmidecode.c: Fix fatal typo in USE_EFI-specific code.
-
-2004-10-01 Roberto Nibali <ratz@tac.ch>
-
- * Makefile: Be LDFLAGS aware.
-
-2004-07-24 Jean Delvare
-
- * util.c: Add missing header include.
-
-2004-06-11 Jean Delvare
-
- * vpddecode.c: Add product IDs "GE" and "T2". Reported by Doug Brenner.
-
-2004-05-02 Jean Delvare
-
- * dmidecode.c: Move legacy DMI entry point decoding to a separate
- function.
- * dmidecode.c: Use a 64 kB buffer for searching entry points,
- instead of repeated 16-byte reads.
- * util.c, util.h: New mem_chunk function. It returns a buffer
- containing a copy of a given chunk of the physical memory.
- * dmidecode.c: Make use of the new mem_chunk function.
-
-2004-04-30 Jean Delvare
-
- * vpddecode.c: Add product ID "JP". Reported by Bernd Krumboeck.
-
-2004-04-22 Jean Delvare
-
- * dmidecode.c, biosdecode.c, ownership.c, types.h: Move common
- WORD-like macros to types.h.
-
-2004-04-21 Jean Delvare
-
- * dmidecode.c, biosdecode.c: Fix my contact information.
- * dmidecode.c: Update copyright year.
-
-2004-04-20 Jean Delvare
-
- * README: Correct Chad Smith's name. Reported by Martin Pool.
-
-2004-04-15 Jean Delvare
-
- * vpddecode.c: Add product ID "PL". Reported by Mark Syms.
-
-2004-04-14 Jean Delvare
-
- * vpddecode.c: Add product ID "PD". Reported by Roger Koot.
-
-2004-04-11 Jean Delvare
-
- * dmidecode.c, Makefile, README: Drop TABLE_LITTLEENDIAN.
- * README: Update manual pages information.
-
-2004-04-02 Jean Delvare
-
- * vpddecode.c: Add product ID "NV". Reported by Shawn Starr.
-
-2004-03-27 Jean Delvare
-
- * vpddecode.c: Add product ID "24". Reported by Paul Sturm.
- * dmidecode.c: Fix two missing comas in string enumerations. Thanks to
- Joshua Goldenhar for reporting the first one.
-
-2004-03-24 Jean Delvare
-
- * vpddecode.c: Add product ID "PJ". Reported by Roger Koot.
- * vpddecode.c: Rename two Netvista systems to use their real name
- instead of machine type.
-
-2004-03-20 Petter Reinholdtsen <pere@hungry.com>
-
- * Makefile: Make it easier to select where to install the binaries
- and manual pages, and to use different paths when building and
- installing.
-
-2004-03-19 Jean Delvare
-
- * vpddecode.c: Add product ID "2A". Reported by Rafael Avila
- de Espindola.
- * version.h: Set version to 2.4.
-
-2004-03-07 Jean Delvare
-
- * biosdecode.c, vpddecode.c: Add a third checksumming method for
- VPD records.
- * vpddecode.c: Add product ID "PI", update "20". Reported by
- Zing Zing Shishak.
-
-2004-03-05 Jean Delvare
-
- * README: Update.
-
-2004-02-25 Jean Delvare
-
- * dmidecode.c: Support CPUID document revision 25 (no change).
- * dmidecode.c: Shorten the EOF error message.
-
-2004-02-23 Jean Delvare
-
- * man/biosdecode.8, man/dmidecode.8, man/ownership.8,
- man/vpddecode.8: New.
- * Makefile: Handle new manual pages.
-
-2003-12-28 Jean Delvare
-
- * vpddecode.c: Add product ID "PT". Reported by Ramiro Barreiro.
-
-2003-12-17 Jean Delvare
-
- * vpddecode.c: Add product ID "RE". Reported by Josef Moellers.
- * vpddecode.c, biosdecode.c: Handle longer VPD records as seen on
- xSeries. These have a different checksumming method.
-
-2003-12-03 Jean Delvare
-
- * vpddecode.c: Add product ID "TT". Reported by Hugues Lepesant.
- * vpddecode.c, biosdecode.c: Fix typo ("Bios" becomes "BIOS").
- * dmidecode.c: Add another exception to the CPUID-supporting CPU list
- ("Pentium III MMX").
- * dmidecode.c: Number devices in multi-device on board device
- information structures (DMI case 10).
-
-2003-11-13 Jean Delvare
-
- * dmidecode.c: Automatically detect architectures on which to use EFI
- (ia64 for now). Suggested by Jeff Moyer.
-
-2003-11-11 Jean Delvare
-
- * vpddecode.c: Add product ID "KX". Reported by Klaus Ade Johnstad,
- confirmed by Pamela Huntley.
- * dmidecode.c: Display CPUID values as decimal, not hexadecimal.
- This is a reversal of the 2003-07-18 change to be consistent with
- /proc/cpuinfo under Linux.
- * dmidecode.c: Fix processor ID decoding for older 80486. Not very
- important since such systems are unlikely to support SMBIOS.
- * dmidecode.c: Modify CPU signature display for AMD processors.
- * vpddecode.c, biosdecode.c: Fix incorrect VPD checksumming.
-
-2003-10-24 Jean Delvare
-
- * dmidecode.c: Add another exception to the CPUID-supporting CPU list.
-
-2003-10-19 Jean Delvare
-
- * README: Clarify why mmap is used. Fix typo.
- * Makefile: Add deleting core to the clean target.
- * version.h: Set version to 2.3.
-
-2003-10-17 Jean Delvare
-
- * biosdecode.c: Use (void) instead of __attribute__ ((unused)) to
- declare that a function parameter isn't used. According to Alexandre
- Duret-Lutz, this is the portable way do to it. Fix typo in comment.
- * dmidecode.c: Fix typo.
-
-2003-10-16 Jean Delvare
-
- * dmidecode.c: Remove useless comparison in dmi_system_boot_status.
- Thanks to Alexandre Duret-Lutz for pointing this out.
- * biosdecode.c: Add a missing length check in acpi_decode. Found
- using Valgrind.
- * biosdecode.c: Fix buffer overrun in main. Found using Valgrind.
-
-2003-10-14 Jean Delvare
-
- * dmidecode.c: Update DMTF reference addresses.
- * dmidecode.c: List two more processors (Athlon64 and Pentium M)
- as x86-class (i.e. supporting CPUID).
-
-2003-10-11 Jean Delvare
-
- Update to support DMTF Master MIF version 030621 (was 021205).
-
- * dmidecode.c: Handle unknown processor voltage.
- * dmidecode.c: Fix typo in event log method.
- * dmidecode.c: One additional processor type (Pentium M).
- * dmidecode.c: Add the AMD Opteron to the list of x86-class
- processors. Thanks to Mike Cooper for providing information.
- * vpddecode.c: New program for decoding a machine's VPD structure
- (only found in IBM machines).
- * Makefile: Update accordingly.
- * Makefile: Fix dependencies for ownership. Add strip target. Various
- cleanups (reordering, comments, optimization and debug flags).
- * README: Update to reflect the addition of the strip target and the
- vpddecode program. Some additional changes and fixes.
-
-2003-10-10 Jean Delvare
-
- * dmidecode.c: Change mmap options to prevent dmidecode from being
- killed by the Linux kernel in some rare cases. Reported by
- Mike Cooper.
- * dmidecode.c: Various code cleanups and optimizations.
-
-2003-10-09 Jean Delvare
-
- * dmidecode.c: Fix a bug that prevented dmidecode to reach DMI tables
- beyond the 2GB memory limit. Reported by Mike Cooper.
- * ownership.c: Add one reference. Code cleanups.
- * CHANGELOG: Fix typo.
-
-2003-10-08 Jean Delvare
-
- * biosdecode.c: Fix potentially wrong checksum on Sony-specific entry.
- * biosdecode.c: Unimportant changes (comment, typo...) in
- Compaq-specific section.
- * biosdecode.c: Add support for VPD (vital product data, IBM-specific).
- * CHANGELOG: Various updates.
-
-2003-10-07 Jean Delvare
-
- * ownership.c: Fix a harmless warning on x86_64. Reported by Mike
- Cooper.
-
-2003-09-19 Jean Delvare
-
- * dmidecode.c: Explicitly say when no SMBIOS nor DMI entry point
- was found. Implicitly suggested by Sergey Leonovich.
-
-2003-09-11 Jean Delvare
-
- * Makefile: Don't use $^ since it isn't supported by BSD make.
- Reported by Hugues Lepesant.
-
-2003-09-05 Jean Delvare
-
- * Makefile: Fix missing ownership dependency for install target.
- Reported by Mario Lang.
-
-2003-08-08 Jean Delvare
-
- * dmidecode.c: Update the README file (mainly the now solved laptop
- and IA-64 issues, and add a section for biosdecode and ownership).
- * version.h: Set version to 2.2.
-
-2003-07-18 Jean Delvare
-
- * dmidecode.c: Display CPUID values as hexadecimal, not decimal.
- * dmidecode.c: Shift the I2C slave address by one bit to the right
- (DMI case 38).
-
-2003-06-27 Jean Delvare
-
- * biosdecode.c: Better display of Compaq-specific entries (thank to
- some documentation).
-
-2003-06-25 Jean Delvare
-
- * dmidecode.c: Remove fp_last (not useful anymore). Reworded the "table
- is unreachable" message to mention the -DUSE_MMAP solution.
-
-2003-06-19 Jean Delvare
-
- * dmidecode.c: Add support for IA-64.
- * Makefile: Add new option CFLAGS modifier lines for IA-64.
-
-2003-06-17 Jean Delvare
-
- * dmidecode.c, biosdecode.c: Move common "util" functions to util.c.
- * util.c, util.h: New.
- * types.h: New.
- * Makefile: Update accordingly.
- * biosdecode.c: Add detection of Compaq-specific entries.
- * ownership.c: New program for finding a machine's ownership tag
- (only found in Compaq machines). Requested by Luc Van de Velde.
- * Makefile: Update again.
-
-2003-06-10 Jean Delvare
-
- * dmidecode.c: Fix typo in IPMI register spacing table.
- * version.h: Set version to 2.1.
-
-2003-06-04 Jean Delvare
-
- * Makefile: Restore optional CFLAGS modifier lines.
- * README: New.
-
-2003-05-30 Jean Delvare
-
- * dmidecode.c: Cleaner handling of unreachable table.
-
-2003-05-27 Jean Delvare
-
- Update to support Intel AP-485 specification (CPUID) revision 023
- (was 021).
-
- * dmidecode.c: Add SBF flag to processor ID (DMI case 4). Add comment
- about new flags returned in ECX.
-
-2003-05-26 Jean Delvare
-
- Update to support SMBIOS specification version 2.3.4 (was 2.3.3).
-
- * dmidecode.c: Add processor and processor upgrade names (DMI case 4).
- * dmidecode.c: Add slot names (DMI case 9).
-
-2003-05-22 Jean Delvare
-
- * dmidecode.c: Fix typo reported by David Wilson (DMI case 6).
-
-2003-03-08 Jean Delvare
-
- * dmidecode.c: Decode more fields according to the IPMI specification
- (DMI case 38).
-
-2003-03-07 Jean Delvare
-
- Fixed IPMI device information (DMI case 38). Thanks to Richard Sharpe
- for pointing the bugs out.
-
- * dmidecode.c: Fix IPMI interface type being shifted by one.
- * dmidecode.c: Fix NV storage device being improperly displayed.
- * dmidecode.c: Reword IPMI specification revision into specification
- version, as suggested in the IPMI specification itself.
- * dmidecode.c: Add a reference to the IPMI specification.
- * dmidecode.c: Show I2C address as hexadecimal.
- * dmidecode.c: Base address is a QWORD, not DWORD.
- * dmidecode.c: Decode some extra fields according to the IPMI
- specification.
-
-2003-03-06 Jean Delvare
-
- * dmidecode.c, biosdecode.c: Move all changelog entries to CHANGELOG.
- * CHANGELOG: New. Format inspired by Heroes' ChangeLog file.
- * dmidecode.c, biosdecode.c, Makefile: Update copyright years.
- * dmidecode.c, biosdecode.c, Makefile: Move version definition to
- version.h. Update dependencies accordingly.
- * version.h: New.
-
-2002-10-21 Jean Delvare
-
- * dmidecode.c: Change supported log type descriptors display.
- * dmidecode.c: Code optimization in event log status.
- * dmidecode.c: Remove extra newline in voltage probe accuracy.
- * dmidecode.c: Display "OEM-specific" if type is 128 or more.
- * dmidecode.c: Do not display Strings on dump if there are no strings.
- * dmidecode.c: Add ASCII-filtering to dmi_string.
- * dmidecode.c: Convert all dates to ISO 8601.
-
-2002-10-18 Jean Delvare
-
- * dmidecode.c: Complete rewrite.
- * dmidecode.c: Now complies with SMBIOS specification 2.3.3.
- * dmidecode.c: Move all non-DMI stuff to biosdecode.c.
- * biosdecode.c: New.
-
-2002-10-15 Jean Delvare
-
- * dmidecode.c: Fix bad index in DMI case 27 (cooling device).
-
-2002-10-14 Jean Delvare
-
- * dmidecode.c: Fix typo in dmi_memory_array_location.
- * dmidecode.c: Replace Kbyte by kB in DMI case 16.
- * dmidecode.c: Add DDR entry in dmi_memory_device_type.
- * dmidecode.c: Fix extra s in SYSID.
-
-2002-10-12 Jean Delvare
-
- * dmidecode.c: Fix maximum cache size and installed size being
- inverted.
- * dmidecode.c: Fix typos in port types.
-
-2002-10-10 Jean Delvare
-
- * dmidecode.c: Remove extra semicolon at the end of
- dmi_memory_array_use.
- * dmidecode.c: Fix compilation warnings.
- * dmidecode.c: Add missing backslash in DMI case 37.
- * dmidecode.c: Fix BIOS ROM size (DMI case 0).
-
-2002-10-05 Jean Delvare
-
- * dmidecode.c: More ACPI decoded.
- * dmidecode.c: More PNP decoded.
- * dmidecode.c: More SYSID decoded.
- * dmidecode.c: PCI Interrupt Routing decoded.
- * dmidecode.c: BIOS32 Service Directory decoded.
- * dmidecode.c: Sony system detection (unconfirmed).
- * dmidecode.c: Checksums verified whenever possible.
- * dmidecode.c: Better checks on file read and close.
- * dmidecode.c: Define VERSION and display version at beginning.
- * dmidecode.c: More secure decoding (won't run off the table in any
- case).
- * dmidecode.c: Do not try to decode more structures than announced.
- * dmidecode.c: Fix an off-by-one error that caused the last address
- being scanned to be 0x100000, not 0xFFFF0 as it should.
-
-2002-09-28 Jean Delvare
-
- * dmidecode.c: Fix missing coma in dmi_bus_name.
- * dmidecode.c: Remove unwanted bitmaskings in dmi_mgmt_dev_type,
- dmi_mgmt_addr_type, dmi_fan_type, dmi_volt_loc, dmi_temp_loc and
- dmi_status.
- * dmidecode.c: Fix DMI table read bug ("dmi: read: Success").
- * dmidecode.c: Make the code pass -W again.
- * dmidecode.c: Fix return value of dmi_card_size.
-
-2002-09-20 Dave Johnson <ddj@cascv.brown.edu>
-
- * dmidecode.c: Fix comparisons in dmi_bus_name.
- * dmidecode.c: Fix comparison in dmi_processor_type.
- * dmidecode.c: Fix bitmasking in dmi_onboard_type.
- * dmidecode.c: Fix return value of dmi_temp_loc.
-
-2002-09-17 Larry Lile <llile@dreamworks.com>
-
- * dmidecode.c: Type 16 & 17 structures displayed per SMBIOS 2.3.1 spec.
-
-2002-08-23 Alan Cox <alan@redhat.com>
-
- * dmidecode.c: Make the code pass -Wall -pedantic by fixing a few
- harmless sign of pointer mismatches.
- * dmidecode.c: Correct main() prototype.
- * dmidecode.c: Check for compilers with wrong type sizes.
-
-2002-08-09 Jean Delvare
-
- * dmidecode.c: Better DMI struct count/size error display.
- * dmidecode.c: More careful memory access in dmi_table.
- * dmidecode.c: DMI case 13 (Language) decoded.
- * dmidecode.c: C++ style comments removed. Commented out code removed.
- * dmidecode.c: DMI 0.0 case handled.
- * dmideocde.c: Fix return value of dmi_port_type and
- dmi_port_connector_type.
-
-2002-08-06 Jean Delvare
-
- * dmidecode.c: Reposition file pointer after DMI table display.
- * dmidecode.c: Disable first RSD PTR checksum (was not correct anyway).
- * dmidecode.c: Show actual DMI struct count and occupied size.
- * dmidecode.c: Check for NULL after malloc.
- * dmidecode.c: Use SEEK_* constants instead of numeric values.
- * dmidecode.c: Code optimization (and warning fix) in DMI cases 10 and
- 14.
- * dmidecode.c: Add else's to avoid unneeded cascaded if's in main loop.
- * dmidecode.c: Code optimization in DMI information display.
- * dmidecode.c: Fix all compilation warnings.
-
-2002-08-03 Mark D. Studebaker <mds@paradyne.com>
-
- * dmidecode.c: Better indent in dump_raw_data.
- * dmidecode.c: Fix return value of dmi_bus_name.
- * dmidecode.c: Additional sensor fields decoded.
- * dmidecode.c: Fix compilation warnings.
-
-2001-12-13 Arjan van de Ven <arjanv@redhat.com>
-
- * dmidecode.c: Fix memory bank type (DMI case 6).
-
-2001-07-02 Matt Domsch <Matt_Domsch@dell.com>
-
- * dmidecode.c: Additional structures displayed per SMBIOS 2.3.1 spec.
diff --git a/Makefile b/Makefile
index 1f54a1f..7aa729d 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# VPD Decode
#
# Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
-# Copyright (C) 2002-2015 Jean Delvare <jdelvare@suse.de>
+# Copyright (C) 2002-2020 Jean Delvare <jdelvare@suse.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -12,8 +12,13 @@
# (at your option) any later version.
#
-CC = gcc
-CFLAGS = -W -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual \
+CC ?= gcc
+# Base CFLAGS can be overridden by environment
+CFLAGS ?= -O2
+# When debugging, disable -O2 and enable -g
+#CFLAGS ?= -g
+
+CFLAGS += -W -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual \
-Wcast-align -Wwrite-strings -Wmissing-prototypes -Winline -Wundef
# Let lseek and mmap support 64-bit wide offsets
@@ -22,12 +27,8 @@ CFLAGS += -D_FILE_OFFSET_BITS=64
#CFLAGS += -DBIGENDIAN
#CFLAGS += -DALIGNMENT_WORKAROUND
-# When debugging, disable -O2 and enable -g.
-CFLAGS += -O2
-#CFLAGS += -g
-
-# Pass linker flags here
-LDFLAGS =
+# Pass linker flags here (can be set from environment too)
+LDFLAGS ?=
DESTDIR =
prefix = /usr/local
@@ -61,8 +62,8 @@ all : $(PROGRAMS)
# Programs
#
-dmidecode : dmidecode.o dmiopt.o dmioem.o util.o
- $(CC) $(LDFLAGS) dmidecode.o dmiopt.o dmioem.o util.o -o $@
+dmidecode : dmidecode.o dmiopt.o dmioem.o dmioutput.o util.o
+ $(CC) $(LDFLAGS) dmidecode.o dmiopt.o dmioem.o dmioutput.o util.o -o $@
biosdecode : biosdecode.o util.o
$(CC) $(LDFLAGS) biosdecode.o util.o -o $@
@@ -78,13 +79,16 @@ vpddecode : vpddecode.o vpdopt.o util.o
#
dmidecode.o : dmidecode.c version.h types.h util.h config.h dmidecode.h \
- dmiopt.h dmioem.h
+ dmiopt.h dmioem.h dmioutput.h
$(CC) $(CFLAGS) -c $< -o $@
dmiopt.o : dmiopt.c config.h types.h util.h dmidecode.h dmiopt.h
$(CC) $(CFLAGS) -c $< -o $@
-dmioem.o : dmioem.c types.h dmidecode.h dmioem.h
+dmioem.o : dmioem.c types.h dmidecode.h dmioem.h dmioutput.h
+ $(CC) $(CFLAGS) -c $< -o $@
+
+dmioutput.o : dmioutput.c types.h dmioutput.h
$(CC) $(CFLAGS) -c $< -o $@
biosdecode.o : biosdecode.c version.h types.h util.h config.h
@@ -134,7 +138,7 @@ uninstall-man :
install-doc :
$(INSTALL_DIR) $(DESTDIR)$(docdir)
$(INSTALL_DATA) README $(DESTDIR)$(docdir)
- $(INSTALL_DATA) CHANGELOG $(DESTDIR)$(docdir)
+ $(INSTALL_DATA) NEWS $(DESTDIR)$(docdir)
$(INSTALL_DATA) AUTHORS $(DESTDIR)$(docdir)
uninstall-doc :
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..504e3fb
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,193 @@
+Version 3.5 (Tue Mar 14 2023)
+ - Decode HPE OEM records 216, 224, 230, 238 and 242.
+ - Fortify entry point length checks.
+ - Add a --no-quirks option.
+ - Drop the CPUID exception list.
+ - Do not let --dump-bin overwrite an existing file.
+ - Ensure /dev/mem is a character device file.
+ - Bug fixes:
+ Fix segmentation fault in HPE OEM record 240
+ - Minor improvements:
+ Typo fixes
+ Write the whole dump file at once
+ Fix a build warning when USE_MMAP isn't set
+
+Version 3.4 (Mon Jun 27 2022)
+ - Support for SMBIOS 3.4.0. This includes new memory device types, new
+ processor upgrades, new slot types and characteristics, decoding of memory
+ module extended speed, new system slot types, new processor characteristics
+ and new format of Processor ID.
+ - Support for SMBIOS 3.5.0. This includes new processor upgrades, BIOS
+ characteristics, new slot characteristics, new on-board device types, new
+ pointing device interface types, and a new record type (type 45 -
+ Firmware Inventory Information).
+ - Decode HPE OEM records 194, 199, 203, 236, 237, 238 and 240.
+ - Bug fixes:
+ Fix OEM vendor name matching
+ Fix ASCII filtering of strings
+ Fix crash with option -u
+ - Minor improvements:
+ Skip details of uninstalled memory modules
+ Don't display the raw CPU ID in quiet mode
+ Improve the formatting of the manual pages
+
+Version 3.3 (Wed Oct 14 2020)
+ - [BUILD] Allow overriding build settings from the environment.
+ - [COMPATIBILITY] Document how the UUID fields are interpreted.
+ - [PORTABILITY] Don't use memcpy on /dev/mem on arm64.
+ - [PORTABILITY] Only scan /dev/mem for entry point on x86.
+ - Support for SMBIOS 3.3.0. This includes new processor names, new port
+ connector types, and new memory device form factors, types and
+ technologies.
+ - Add bios-revision, firmware-revision and system-sku-number to -s option.
+ - Use the most appropriate unit for cache size.
+ - Decode system slot base bus width and peers.
+ - Important bug fixes:
+ Fix Redfish Hostname print length
+ Fix formatting of TPM table output
+ Fix System Slot Information for PCIe SSD
+ Don't choke on invalid processor voltage
+ - Use the most appropriate unit for cache size.
+
+Version 3.2 (Wed Sep 14 2018)
+ - [COMPATIBILITY] The UUID is now displayed using lowercase letters, per
+ RFC 4122 (#53569). You must ensure that any code parsing it is
+ case-insensitive.
+ - Support for SMBIOS 3.2.0. This includes new processor names, new socket
+ and port connector types, new system slot state and property, and support
+ for non-volatile memory (NVDIMM).
+ - Support for Redfish management controllers.
+ - A new command line option to query a specific structure by its handle.
+ - A new command line option to query the system family string.
+ - Support for 3 ThinkPad-specific structures (patch #9642).
+ - Support for HPE's new company name.
+ - Support UEFI on FreeBSD.
+ - Important bug fixes:
+ Fix firmware version of TPM device
+ Fix the HPE UEFI feature flag check
+ - (biosdecode) A new command line option to fully decode PIR information
+ (support request #109339).
+
+Version 3.1 (Tue May 23 2017)
+ - Support for SMBIOS 3.1.0 and 3.1.1. This includes new chassis types, new
+ processor family names, new processor family upgrade names, and new slot
+ types, as well as support of larger BIOS ROM sizes and cache sizes, and a
+ new structure type (43, TPM Device.)
+ - A new command line option to query OEM strings.
+ - All error messages are now printed on stderr (#47274, #48158.)
+ - Several bug fixes related to 64-bit entry points (#50037 and more.)
+ - Important bug fixes:
+ #46176 (Unexpected end of file error)
+ #46066 (Crash with SIGBUS)
+ - Various minor fixes, improvements and cleanups.
+
+Version 3.0 (Thu Sep 03 2015)
+ - Support for SMBIOS 3.0. This includes new chassis types, new
+ processor family names, new processor family upgrade names, new slot
+ types, and new memory device types.
+ - Support for the new 64-bit entry point (_SM3_) defined in SMBIOS 3.0.
+ - Support for the new kernel interface (as of Linux v4.2) as an
+ alternative to relying /dev/mem to access the entry point and DMI
+ table.
+ - Decoding of Acer-specific DMI type 170.
+ - Decoding of HP-specific DMI types 212, 219 and 233.
+ - Various minor fixes and output format cleanups.
+
+Version 2.12 (Wed Apr 17 2013)
+ - Support of the SMBIOS 2.8.0 specification.
+
+Version 2.11 (Wed Jan 19 2011)
+ - Support of the SMBIOS 2.7.0 specification:
+ - UEFI support
+ - Virtual machine flags in BIOS characteristics
+ - Limited support for the Management Controller Host Interface
+ - Various fixes that address stability.
+
+Version 2.10 (Sun Nov 23 2008)
+ - Support for Solaris (x86 only, of course).
+ - Possibility to dump the SMBIOS/DMI table to a small binary file
+ (option --dump-bin).
+ - Possibility to read the SMBIOS/DMI table from such binary files
+ (option --from-dump).
+ - Support for SMBIOS 2.6. This includes new chassis types, new
+ processor family names, new processor family upgrade names, bus
+ address for system slots, and a new entry type for on-board devices,
+ amongst many other minor changes.
+ - Support for DMI entry type 31 (Boot integrity services).
+ - Many processor family names taken from the CIM Schema document.
+ - (vpddecode) No longer ask users to report broken records.
+ - (vpddecode) Fix --quiet option.
+
+Version 2.9 (Mon Feb 26 2007)
+ - Support of the SMBIOS 2.5 specification. It adds many enumerated
+ values for recent hardware, as well as CPU core and thread count
+ reporting.
+ - Decoding of 3 HP-specific entries. More vendor-specific entries can
+ be supported later if vendors contribute code or documentation.
+ - Run-time detection of EFI, so that a single binary can support
+ Intel-based Macintosh machines and regular x86 machines.
+ - Better IA-64 support.
+ - Fixes to the decoding of individual fields, including the CPU
+ signature of recent CPU models.
+ - (biosdecode) Support of the FJKEYINF entry point type (for Fujitsu laptops).
+ - (vpddecode) The product name look-up table was dropped. It was unreliable
+ and a burden to maintain.
+ - biosdecode, ownership and vpddecode are no longer built on IA-64.
+
+Version 2.8 (Sat Feb 04 2006)
+ - Option --string has four additional keywords available:
+ system-uuid, chassis-type, processor-family and processor-frequency.
+ These needed additional work because, technically speaking, they are
+ not DMI strings.
+ - IPMI interface type SSIF was added. This is a new interface type
+ defined by IPMI 2.0.
+ - (vpddecode) New --string option, much similar in spirit to
+ dmidecode's. Available keywords are bios-build-id, box-serial-number,
+ motherboard-serial-number, machine-type-model and bios-release-date.
+ - (vpddecode) 9 product names were added to the lookup table.
+ - A few bug fixes, cleanups and minor improvements all around the place.
+
+Version 2.7 (Thu Aug 04 2005)
+ - New command line interface. For example, it is now possible to limit
+ the output of dmidecode to a given DMI type, or to extract a single
+ string from the DMI table. The documentation has been updated
+ accordingly.
+ - The default output of dmidecode was slightly modified to be more
+ easily readable by humans. This might break tools parsing its output.
+ Such tools may benefit from the new command line interface, although
+ this interface shouldn't be considered stable until version 2.8.
+ - (vpddecode) New command line interface.
+ - (vpddecode) 6 product names were added.
+
+Version 2.6 (Mon Feb 28 2005)
+ - Fixes a 2 GB memory limit regression.
+ - Basic command-line handling.
+ - BeOS and Cygwin support.
+
+Version 2.5 (Thu Nov 11 2004)
+ - Code cleanups.
+ - Compatibility fixes.
+ - Documentation updates.
+
+Version 2.4 (Fri Mar 19 2004)
+ - Manual pages added.
+ - (vpddecode) Many improvements.
+ - A few fixes and minor improvements.
+
+Version 2.3 (Sun Oct 19 2003)
+ - Support of x86_64 systems.
+ - Support of systems with 2 GB and more memory.
+ - Loads of bug fixes and corrections.
+ - New tool "vpddecode" added.
+
+Version 2.2 (Fri Aug 08 2003)
+ - Support of IA-64 systems.
+ - Support of IBM and Fujitsu-Siemens laptops.
+ - Many minor bug fixes.
+ - New tool "ownership" added.
+
+Version 2.1 (Tue Jun 10 2003)
+ - Support of the SMBIOS 2.3.4 specification.
+ - Better support of IPMI.
+ - Minor bugs fixed.
+ - Documentation added.
diff --git a/README b/README
index f612b36..c87e52c 100644
--- a/README
+++ b/README
@@ -56,7 +56,7 @@ Each tool has a manual page, found in the "man" subdirectory. Manual pages
are installed by "make install". See these manual pages for command line
interface details and tool specific information.
-For an history of the changes made to dmidecode, see the CHANGELOG file.
+For an history of the changes made to dmidecode, see the NEWS file.
If you need help, your best chances are to visit the web page (see the
INSTALLATION section above) or to get in touch with the developers directly.
diff --git a/biosdecode.c b/biosdecode.c
index ad3d4bc..99a27fe 100644
--- a/biosdecode.c
+++ b/biosdecode.c
@@ -73,12 +73,16 @@ struct opt
{
const char *devmem;
unsigned int flags;
+ unsigned char pir;
};
static struct opt opt;
#define FLAG_VERSION (1 << 0)
#define FLAG_HELP (1 << 1)
+#define PIR_SHORT 0
+#define PIR_FULL 1
+
struct bios_entry {
const char *anchor;
size_t anchor_len; /* computed */
@@ -351,7 +355,7 @@ static void pir_slot_number(u8 code)
if (code == 0)
printf(" on-board");
else
- printf(" slot number %u", code);
+ printf(" slot %u", code);
}
static size_t pir_length(const u8 *p)
@@ -359,16 +363,26 @@ static size_t pir_length(const u8 *p)
return WORD(p + 6);
}
+static void pir_link_bitmap(char letter, const u8 *p)
+{
+ if (p[0] == 0) /* Not connected */
+ return;
+
+ printf("\t\tINT%c#: Link 0x%02x, IRQ Bitmap", letter, p[0]);
+ pir_irqs(WORD(p + 1));
+ printf("\n");
+}
+
static int pir_decode(const u8 *p, size_t len)
{
- int i;
+ int i, n;
if (len < 32 || !checksum(p, WORD(p + 6)))
return 0;
printf("PCI Interrupt Routing %u.%u present.\n",
p[5], p[4]);
- printf("\tRouter ID: %02x:%02x.%1x\n",
+ printf("\tRouter Device: %02x:%02x.%1x\n",
p[8], p[9]>>3, p[9] & 0x07);
printf("\tExclusive IRQs:");
pir_irqs(WORD(p + 10));
@@ -380,38 +394,19 @@ static int pir_decode(const u8 *p, size_t len)
printf("\tMiniport Data: 0x%08X\n",
DWORD(p + 16));
- for (i = 1; i <= (WORD(p + 6) - 32) / 16; i++)
+ n = (len - 32) / 16;
+ for (i = 1, p += 32; i <= n; i++, p += 16)
{
- printf("\tSlot Entry %u: ID %02x:%02x,",
- i, p[(i + 1) * 16], p[(i + 1) * 16 + 1] >> 3);
- pir_slot_number(p[(i + 1) * 16 + 14]);
+ printf("\tDevice: %02x:%02x,", p[0], p[1] >> 3);
+ pir_slot_number(p[14]);
printf("\n");
-/* printf("\tSlot Entry %u\n", i);
- printf("\t\tID: %02x:%02x\n",
- p[(i + 1) * 16], p[(i + 1) * 16 + 1] >> 3);
- printf("\t\tLink Value for INTA#: %u\n",
- p[(i + 1) * 16 + 2]);
- printf("\t\tIRQ Bitmap for INTA#:");
- pir_irqs(WORD(p + (i + 1) * 16 + 3));
- printf("\n");
- printf("\t\tLink Value for INTB#: %u\n",
- p[(i + 1) * 16 + 5]);
- printf("\t\tIRQ Bitmap for INTB#:");
- pir_irqs(WORD(p + (i + 1) * 16 + 6));
- printf("\n");
- printf("\t\tLink Value for INTC#: %u\n",
- p[(i + 1) * 16 + 8]);
- printf("\t\tIRQ Bitmap for INTC#:");
- pir_irqs(WORD(p + (i + 1) * 16 + 9));
- printf("\n");
- printf("\t\tLink Value for INTD#: %u\n",
- p[(i + 1) * 16 + 11]);
- printf("\t\tIRQ Bitmap for INTD#:");
- pir_irqs(WORD(p + (i + 1) * 16 + 12));
- printf("\n");
- printf("\t\tSlot Number:");
- pir_slot_number(p[(i + 1) * 16 + 14]);
- printf("\n");*/
+ if (opt.pir == PIR_FULL)
+ {
+ pir_link_bitmap('A', p + 2);
+ pir_link_bitmap('B', p + 5);
+ pir_link_bitmap('C', p + 8);
+ pir_link_bitmap('D', p + 11);
+ }
}
return 1;
@@ -616,6 +611,7 @@ static int parse_command_line(int argc, char * const argv[])
const char *optstring = "d:hV";
struct option longopts[] = {
{ "dev-mem", required_argument, NULL, 'd' },
+ { "pir", required_argument, NULL, 'P' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
@@ -627,6 +623,10 @@ static int parse_command_line(int argc, char * const argv[])
case 'd':
opt.devmem = optarg;
break;
+ case 'P':
+ if (strcmp(optarg, "full") == 0)
+ opt.pir = PIR_FULL;
+ break;
case 'h':
opt.flags |= FLAG_HELP;
break;
@@ -646,6 +646,7 @@ static void print_help(void)
"Usage: biosdecode [OPTIONS]\n"
"Options are:\n"
" -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n"
+ " --pir full Decode the details of the PCI IRQ routing table\n"
" -h, --help Display this help text and exit\n"
" -V, --version Display the version and exit\n";
diff --git a/config.h b/config.h
index e39091f..4237355 100644
--- a/config.h
+++ b/config.h
@@ -26,4 +26,9 @@
#define ALIGNMENT_WORKAROUND
#endif
+/* Avoid unaligned memcpy on /dev/mem */
+#ifdef __aarch64__
+#define USE_SLOW_MEMCPY
+#endif
+
#endif
diff --git a/dmidecode.c b/dmidecode.c
index 6559567..54f59c1 100644
--- a/dmidecode.c
+++ b/dmidecode.c
@@ -2,7 +2,7 @@
* DMI Decode
*
* Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
- * Copyright (C) 2002-2017 Jean Delvare <jdelvare@suse.de>
+ * Copyright (C) 2002-2020 Jean Delvare <jdelvare@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@
* are deemed to be part of the source code.
*
* Unless specified otherwise, all references are aimed at the "System
- * Management BIOS Reference Specification, Version 3.1.1" document,
+ * Management BIOS Reference Specification, Version 3.2.0" document,
* available from http://www.dmtf.org/standards/smbios.
*
* Note to contributors:
@@ -56,13 +56,23 @@
* - "PC Client Platform TPM Profile (PTP) Specification"
* Family "2.0", Level 00, Revision 00.43, January 26, 2015
* https://trustedcomputinggroup.org/pc-client-platform-tpm-profile-ptp-specification/
+ * - "RedFish Host Interface Specification" (DMTF DSP0270)
+ * https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf
*/
+#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#ifdef __FreeBSD__
+#include <errno.h>
+#include <kenv.h>
+#endif
#include "version.h"
#include "config.h"
@@ -71,11 +81,14 @@
#include "dmidecode.h"
#include "dmiopt.h"
#include "dmioem.h"
+#include "dmioutput.h"
#define out_of_spec "<OUT OF SPEC>"
static const char *bad_index = "<BAD INDEX>";
-#define SUPPORTED_SMBIOS_VER 0x030101
+enum cpuid_type cpuid_type = cpuid_none;
+
+#define SUPPORTED_SMBIOS_VER 0x030500
#define FLAG_NO_FILE_OFFSET (1 << 0)
#define FLAG_STOP_AT_EOT (1 << 1)
@@ -100,13 +113,19 @@ int is_printable(const u8 *data, int len)
return 1;
}
-const char *dmi_string(const struct dmi_header *dm, u8 s)
+/* Replace non-ASCII characters with dots */
+static void ascii_filter(char *bp, size_t len)
{
- char *bp = (char *)dm->data;
- size_t i, len;
+ size_t i;
- if (s == 0)
- return "Not Specified";
+ for (i = 0; i < len; i++)
+ if (bp[i] < 32 || bp[i] >= 127)
+ bp[i] = '.';
+}
+
+static char *_dmi_string(const struct dmi_header *dm, u8 s, int filter)
+{
+ char *bp = (char *)dm->data;
bp += dm->length;
while (s > 1 && *bp)
@@ -117,16 +136,24 @@ const char *dmi_string(const struct dmi_header *dm, u8 s)
}
if (!*bp)
- return bad_index;
+ return NULL;
- if (!(opt.flags & FLAG_DUMP))
- {
- /* ASCII filtering */
- len = strlen(bp);
- for (i = 0; i < len; i++)
- if (bp[i] < 32 || bp[i] == 127)
- bp[i] = '.';
- }
+ if (filter)
+ ascii_filter(bp, strlen(bp));
+
+ return bp;
+}
+
+const char *dmi_string(const struct dmi_header *dm, u8 s)
+{
+ char *bp;
+
+ if (s == 0)
+ return "Not Specified";
+
+ bp = _dmi_string(dm, s, 1);
+ if (bp == NULL)
+ return bad_index;
return bp;
}
@@ -177,12 +204,15 @@ static const char *dmi_smbios_structure_type(u8 code)
"Additional Information",
"Onboard Device",
"Management Controller Host Interface",
- "TPM Device", /* 43 */
+ "TPM Device",
+ "Processor",
+ "Firmware",
+ "String Property" /* 46 */
};
if (code >= 128)
return "OEM-specific";
- if (code <= 43)
+ if (code <= 46)
return type[code];
return out_of_spec;
}
@@ -196,58 +226,54 @@ static int dmi_bcd_range(u8 value, u8 low, u8 high)
return 1;
}
-static void dmi_dump(const struct dmi_header *h, const char *prefix)
+static void dmi_dump(const struct dmi_header *h)
{
+ static char raw_data[48];
int row, i;
- const char *s;
+ unsigned int off;
+ char *s;
- printf("%sHeader and Data:\n", prefix);
+ pr_list_start("Header and Data", NULL);
for (row = 0; row < ((h->length - 1) >> 4) + 1; row++)
{
- printf("%s\t", prefix);
+ off = 0;
for (i = 0; i < 16 && i < h->length - (row << 4); i++)
- printf("%s%02X", i ? " " : "",
+ off += sprintf(raw_data + off, i ? " %02X" : "%02X",
(h->data)[(row << 4) + i]);
- printf("\n");
+ pr_list_item(raw_data);
}
+ pr_list_end();
if ((h->data)[h->length] || (h->data)[h->length + 1])
{
- printf("%sStrings:\n", prefix);
+ pr_list_start("Strings", NULL);
i = 1;
- while ((s = dmi_string(h, i++)) != bad_index)
+ while ((s = _dmi_string(h, i++, !(opt.flags & FLAG_DUMP))))
{
if (opt.flags & FLAG_DUMP)
{
int j, l = strlen(s) + 1;
+
for (row = 0; row < ((l - 1) >> 4) + 1; row++)
{
- printf("%s\t", prefix);
+ off = 0;
for (j = 0; j < 16 && j < l - (row << 4); j++)
- printf("%s%02X", j ? " " : "",
+ off += sprintf(raw_data + off,
+ j ? " %02X" : "%02X",
(unsigned char)s[(row << 4) + j]);
- printf("\n");
+ pr_list_item(raw_data);
}
/* String isn't filtered yet so do it now */
- printf("%s\t\"", prefix);
- while (*s)
- {
- if (*s < 32 || *s == 127)
- fputc('.', stdout);
- else
- fputc(*s, stdout);
- s++;
- }
- printf("\"\n");
+ ascii_filter(s, l - 1);
}
- else
- printf("%s\t%s\n", prefix, s);
+ pr_list_item("%s", s);
}
+ pr_list_end();
}
}
/* shift is 0 if the value is in bytes, 1 if it is in kilobytes */
-static void dmi_print_memory_size(u64 code, int shift)
+void dmi_print_memory_size(const char *attr, u64 code, int shift)
{
unsigned long capacity;
u16 split[7];
@@ -287,7 +313,7 @@ static void dmi_print_memory_size(u64 code, int shift)
else
capacity = split[i];
- printf(" %lu %s", capacity, unit[i + shift]);
+ pr_attr(attr, "%lu %s", capacity, unit[i + shift]);
}
/*
@@ -296,10 +322,19 @@ static void dmi_print_memory_size(u64 code, int shift)
static void dmi_bios_runtime_size(u32 code)
{
+ const char *format;
+
if (code & 0x000003FF)
- printf(" %u bytes", code);
+ {
+ format = "%u bytes";
+ }
else
- printf(" %u kB", code >> 10);
+ {
+ format = "%u kB";
+ code >>= 10;
+ }
+
+ pr_attr("Runtime Size", format, code);
}
static void dmi_bios_rom_size(u8 code1, u16 code2)
@@ -309,12 +344,15 @@ static void dmi_bios_rom_size(u8 code1, u16 code2)
};
if (code1 != 0xFF)
- printf(" %u kB", (code1 + 1) << 6);
+ {
+ u64 s = { .l = (code1 + 1) << 6 };
+ dmi_print_memory_size("ROM Size", s, 1);
+ }
else
- printf(" %u %s", code2 & 0x3FFF, unit[code2 >> 14]);
+ pr_attr("ROM Size", "%u %s", code2 & 0x3FFF, unit[code2 >> 14]);
}
-static void dmi_bios_characteristics(u64 code, const char *prefix)
+static void dmi_bios_characteristics(u64 code)
{
/* 7.1.1 */
static const char *characteristics[] = {
@@ -355,18 +393,16 @@ static void dmi_bios_characteristics(u64 code, const char *prefix)
*/
if (code.l & (1 << 3))
{
- printf("%s%s\n",
- prefix, characteristics[0]);
+ pr_list_item("%s", characteristics[0]);
return;
}
for (i = 4; i <= 31; i++)
if (code.l & (1 << i))
- printf("%s%s\n",
- prefix, characteristics[i - 3]);
+ pr_list_item("%s", characteristics[i - 3]);
}
-static void dmi_bios_characteristics_x1(u8 code, const char *prefix)
+static void dmi_bios_characteristics_x1(u8 code)
{
/* 7.1.2.1 */
static const char *characteristics[] = {
@@ -383,11 +419,10 @@ static void dmi_bios_characteristics_x1(u8 code, const char *prefix)
for (i = 0; i <= 7; i++)
if (code & (1 << i))
- printf("%s%s\n",
- prefix, characteristics[i]);
+ pr_list_item("%s", characteristics[i]);
}
-static void dmi_bios_characteristics_x2(u8 code, const char *prefix)
+static void dmi_bios_characteristics_x2(u8 code)
{
/* 37.1.2.2 */
static const char *characteristics[] = {
@@ -395,21 +430,23 @@ static void dmi_bios_characteristics_x2(u8 code, const char *prefix)
"Function key-initiated network boot is supported",
"Targeted content distribution is supported",
"UEFI is supported",
- "System is a virtual machine" /* 4 */
+ "System is a virtual machine",
+ "Manufacturing mode is supported",
+ "Manufacturing mode is enabled" /* 6 */
};
int i;
- for (i = 0; i <= 4; i++)
+ for (i = 0; i <= 6; i++)
if (code & (1 << i))
- printf("%s%s\n",
- prefix, characteristics[i]);
+ pr_list_item("%s", characteristics[i]);
}
/*
* 7.2 System Information (Type 1)
*/
-static void dmi_system_uuid(const u8 *p, u16 ver)
+static void dmi_system_uuid(void (*print_cb)(const char *name, const char *format, ...),
+ const char *attr, const u8 *p, u16 ver)
{
int only0xFF = 1, only0x00 = 1;
int i;
@@ -422,12 +459,18 @@ static void dmi_system_uuid(const u8 *p, u16 ver)
if (only0xFF)
{
- printf("Not Present");
+ if (print_cb)
+ print_cb(attr, "Not Present");
+ else
+ printf("Not Present\n");
return;
}
if (only0x00)
{
- printf("Not Settable");
+ if (print_cb)
+ print_cb(attr, "Not Settable");
+ else
+ printf("Not Settable\n");
return;
}
@@ -440,13 +483,29 @@ static void dmi_system_uuid(const u8 *p, u16 ver)
* for older versions.
*/
if (ver >= 0x0206)
- printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
- p[3], p[2], p[1], p[0], p[5], p[4], p[7], p[6],
- p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+ {
+ if (print_cb)
+ print_cb(attr,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ p[3], p[2], p[1], p[0], p[5], p[4], p[7], p[6],
+ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+ else
+ printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+ p[3], p[2], p[1], p[0], p[5], p[4], p[7], p[6],
+ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+ }
else
- printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
- p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+ {
+ if (print_cb)
+ print_cb(attr,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
+ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+ else
+ printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
+ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+ }
}
static const char *dmi_system_wake_up_type(u8 code)
@@ -473,7 +532,7 @@ static const char *dmi_system_wake_up_type(u8 code)
* 7.3 Base Board Information (Type 2)
*/
-static void dmi_base_board_features(u8 code, const char *prefix)
+static void dmi_base_board_features(u8 code)
{
/* 7.3.1 */
static const char *features[] = {
@@ -485,17 +544,17 @@ static void dmi_base_board_features(u8 code, const char *prefix)
};
if ((code & 0x1F) == 0)
- printf(" None\n");
+ pr_list_start("Features", "%s", "None");
else
{
int i;
- printf("\n");
+ pr_list_start("Features", NULL);
for (i = 0; i <= 4; i++)
if (code & (1 << i))
- printf("%s%s\n",
- prefix, features[i]);
+ pr_list_item("%s", features[i]);
}
+ pr_list_end();
}
static const char *dmi_base_board_type(u8 code)
@@ -522,15 +581,14 @@ static const char *dmi_base_board_type(u8 code)
return out_of_spec;
}
-static void dmi_base_board_handles(u8 count, const u8 *p, const char *prefix)
+static void dmi_base_board_handles(u8 count, const u8 *p)
{
int i;
- printf("%sContained Object Handles: %u\n",
- prefix, count);
+ pr_list_start("Contained Object Handles", "%u", count);
for (i = 0; i < count; i++)
- printf("%s\t0x%04X\n",
- prefix, WORD(p + sizeof(u16) * i));
+ pr_list_item("0x%04X", WORD(p + sizeof(u16) * i));
+ pr_list_end();
}
/*
@@ -632,40 +690,42 @@ static const char *dmi_chassis_security_status(u8 code)
static void dmi_chassis_height(u8 code)
{
if (code == 0x00)
- printf(" Unspecified");
+ pr_attr("Height", "Unspecified");
else
- printf(" %u U", code);
+ pr_attr("Height", "%u U", code);
}
static void dmi_chassis_power_cords(u8 code)
{
if (code == 0x00)
- printf(" Unspecified");
+ pr_attr("Number Of Power Cords", "Unspecified");
else
- printf(" %u", code);
+ pr_attr("Number Of Power Cords", "%u", code);
}
-static void dmi_chassis_elements(u8 count, u8 len, const u8 *p, const char *prefix)
+static void dmi_chassis_elements(u8 count, u8 len, const u8 *p)
{
int i;
- printf("%sContained Elements: %u\n",
- prefix, count);
+ pr_list_start("Contained Elements", "%u", count);
for (i = 0; i < count; i++)
{
if (len >= 0x03)
{
- printf("%s\t%s (",
- prefix, p[i * len] & 0x80 ?
+ const char *type;
+
+ type = (p[i * len] & 0x80) ?
dmi_smbios_structure_type(p[i * len] & 0x7F) :
- dmi_base_board_type(p[i * len] & 0x7F));
+ dmi_base_board_type(p[i * len] & 0x7F);
+
if (p[1 + i * len] == p[2 + i * len])
- printf("%u", p[1 + i * len]);
+ pr_list_item("%s (%u)", type, p[1 + i * len]);
else
- printf("%u-%u", p[1 + i * len], p[2 + i * len]);
- printf(")\n");
+ pr_list_item("%s (%u-%u)", type, p[1 + i * len],
+ p[2 + i * len]);
}
}
+ pr_list_end();
}
/*
@@ -878,6 +938,7 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
{ 0xCC, "z/Architecture" },
{ 0xCD, "Core i5" },
{ 0xCE, "Core i3" },
+ { 0xCF, "Core i9" },
{ 0xD2, "C7-M" },
{ 0xD3, "C7-D" },
@@ -923,6 +984,10 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
{ 0x140, "WinChip" },
{ 0x15E, "DSP" },
{ 0x1F4, "Video Processor" },
+
+ { 0x200, "RV32" },
+ { 0x201, "RV64" },
+ { 0x202, "RV128" },
};
/*
* Note to developers: when adding entries to this list, check if
@@ -980,115 +1045,58 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
}
}
-static void dmi_processor_id(const struct dmi_header *h, const char *prefix)
+static enum cpuid_type dmi_get_cpuid_type(const struct dmi_header *h)
{
- /* Intel AP-485 revision 36, table 2-4 */
- static const char *flags[32] = {
- "FPU (Floating-point unit on-chip)", /* 0 */
- "VME (Virtual mode extension)",
- "DE (Debugging extension)",
- "PSE (Page size extension)",
- "TSC (Time stamp counter)",
- "MSR (Model specific registers)",
- "PAE (Physical address extension)",
- "MCE (Machine check exception)",
- "CX8 (CMPXCHG8 instruction supported)",
- "APIC (On-chip APIC hardware supported)",
- NULL, /* 10 */
- "SEP (Fast system call)",
- "MTRR (Memory type range registers)",
- "PGE (Page global enable)",
- "MCA (Machine check architecture)",
- "CMOV (Conditional move instruction supported)",
- "PAT (Page attribute table)",
- "PSE-36 (36-bit page size extension)",
- "PSN (Processor serial number present and enabled)",
- "CLFSH (CLFLUSH instruction supported)",
- NULL, /* 20 */
- "DS (Debug store)",
- "ACPI (ACPI supported)",
- "MMX (MMX technology supported)",
- "FXSR (FXSAVE and FXSTOR instructions supported)",
- "SSE (Streaming SIMD extensions)",
- "SSE2 (Streaming SIMD extensions 2)",
- "SS (Self-snoop)",
- "HTT (Multi-threading)",
- "TM (Thermal monitor supported)",
- NULL, /* 30 */
- "PBE (Pending break enabled)" /* 31 */
- };
const u8 *data = h->data;
const u8 *p = data + 0x08;
- u32 eax, edx;
- int sig = 0;
u16 type;
type = (data[0x06] == 0xFE && h->length >= 0x2A) ?
WORD(data + 0x28) : data[0x06];
- /*
- * This might help learn about new processors supporting the
- * CPUID instruction or another form of identification.
- */
- printf("%sID: %02X %02X %02X %02X %02X %02X %02X %02X\n",
- prefix, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
-
if (type == 0x05) /* 80386 */
{
- u16 dx = WORD(p);
- /*
- * 80386 have a different signature.
- */
- printf("%sSignature: Type %u, Family %u, Major Stepping %u, Minor Stepping %u\n",
- prefix, dx >> 12, (dx >> 8) & 0xF,
- (dx >> 4) & 0xF, dx & 0xF);
- return;
+ return cpuid_80386;
}
- if (type == 0x06) /* 80486 */
+ else if (type == 0x06) /* 80486 */
{
u16 dx = WORD(p);
/*
* Not all 80486 CPU support the CPUID instruction, we have to find
- * wether the one we have here does or not. Note that this trick
+ * whether the one we have here does or not. Note that this trick
* works only because we know that 80486 must be little-endian.
*/
if ((dx & 0x0F00) == 0x0400
&& ((dx & 0x00F0) == 0x0040 || (dx & 0x00F0) >= 0x0070)
&& ((dx & 0x000F) >= 0x0003))
- sig = 1;
+ return cpuid_x86_intel;
else
- {
- printf("%sSignature: Type %u, Family %u, Model %u, Stepping %u\n",
- prefix, (dx >> 12) & 0x3, (dx >> 8) & 0xF,
- (dx >> 4) & 0xF, dx & 0xF);
- return;
- }
+ return cpuid_80486;
}
else if ((type >= 0x100 && type <= 0x101) /* ARM */
|| (type >= 0x118 && type <= 0x119)) /* ARM */
{
- u32 midr = DWORD(p);
/*
- * The format of this field was not defined for ARM processors
- * before version 3.1.0 of the SMBIOS specification, so we
- * silently skip it if it reads all zeroes.
+ * The field's format depends on the processor's support of
+ * the SMCCC_ARCH_SOC_ID architectural call. Software can determine
+ * the support for SoC ID by examining the Processor Characteristics field
+ * for "Arm64 SoC ID" bit.
*/
- if (midr == 0)
- return;
- printf("%sSignature: Implementor 0x%02x, Variant 0x%x, Architecture %u, Part 0x%03x, Revision %u\n",
- prefix, midr >> 24, (midr >> 20) & 0xF,
- (midr >> 16) & 0xF, (midr >> 4) & 0xFFF, midr & 0xF);
- return;
+ if (h->length >= 0x28
+ && (WORD(data + 0x26) & (1 << 9)))
+ return cpuid_arm_soc_id;
+ else
+ return cpuid_arm_legacy;
}
else if ((type >= 0x0B && type <= 0x15) /* Intel, Cyrix */
|| (type >= 0x28 && type <= 0x2F) /* Intel */
|| (type >= 0xA1 && type <= 0xB3) /* Intel */
|| type == 0xB5 /* Intel */
|| (type >= 0xB9 && type <= 0xC7) /* Intel */
- || (type >= 0xCD && type <= 0xCE) /* Intel */
+ || (type >= 0xCD && type <= 0xCF) /* Intel */
|| (type >= 0xD2 && type <= 0xDB) /* VIA, Intel */
|| (type >= 0xDD && type <= 0xE0)) /* Intel */
- sig = 1;
+ return cpuid_x86_intel;
else if ((type >= 0x18 && type <= 0x1D) /* AMD */
|| type == 0x1F /* AMD */
|| (type >= 0x38 && type <= 0x3F) /* AMD */
@@ -1097,71 +1105,180 @@ static void dmi_processor_id(const struct dmi_header *h, const char *prefix)
|| (type >= 0x83 && type <= 0x8F) /* AMD */
|| (type >= 0xB6 && type <= 0xB7) /* AMD */
|| (type >= 0xE4 && type <= 0xEF)) /* AMD */
- sig = 2;
- else if (type == 0x01 || type == 0x02)
- {
- const char *version = dmi_string(h, data[0x10]);
- /*
- * Some X86-class CPU have family "Other" or "Unknown". In this case,
- * we use the version string to determine if they are known to
- * support the CPUID instruction.
- */
- if (strncmp(version, "Pentium III MMX", 15) == 0
- || strncmp(version, "Intel(R) Core(TM)2", 18) == 0
- || strncmp(version, "Intel(R) Pentium(R)", 19) == 0
- || strcmp(version, "Genuine Intel(R) CPU U1400") == 0)
- sig = 1;
- else if (strncmp(version, "AMD Athlon(TM)", 14) == 0
- || strncmp(version, "AMD Opteron(tm)", 15) == 0
- || strncmp(version, "Dual-Core AMD Opteron(tm)", 25) == 0)
- sig = 2;
- else
- return;
- }
- else /* neither X86 nor ARM */
- return;
+ return cpuid_x86_amd;
+
+ /* neither X86 nor ARM */
+ return cpuid_none;
+}
+
+void dmi_print_cpuid(void (*print_cb)(const char *name, const char *format, ...),
+ const char *label, enum cpuid_type sig, const u8 *p)
+{
+ u32 eax, midr, jep106, soc_revision;
+ u16 dx;
- /*
- * Extra flags are now returned in the ECX register when one calls
- * the CPUID instruction. Their meaning is explained in table 3-5, but
- * DMI doesn't support this yet.
- */
- eax = DWORD(p);
- edx = DWORD(p + 4);
switch (sig)
{
- case 1: /* Intel */
- printf("%sSignature: Type %u, Family %u, Model %u, Stepping %u\n",
- prefix, (eax >> 12) & 0x3,
- ((eax >> 20) & 0xFF) + ((eax >> 8) & 0x0F),
- ((eax >> 12) & 0xF0) + ((eax >> 4) & 0x0F),
- eax & 0xF);
+ case cpuid_80386:
+ dx = WORD(p);
+ /*
+ * 80386 have a different signature.
+ */
+ print_cb(label,
+ "Type %u, Family %u, Major Stepping %u, Minor Stepping %u",
+ dx >> 12, (dx >> 8) & 0xF,
+ (dx >> 4) & 0xF, dx & 0xF);
+ return;
+
+ case cpuid_80486:
+ dx = WORD(p);
+ print_cb(label,
+ "Type %u, Family %u, Model %u, Stepping %u",
+ (dx >> 12) & 0x3, (dx >> 8) & 0xF,
+ (dx >> 4) & 0xF, dx & 0xF);
+ return;
+
+ case cpuid_arm_legacy: /* ARM before SOC ID */
+ midr = DWORD(p);
+ /*
+ * The format of this field was not defined for ARM processors
+ * before version 3.1.0 of the SMBIOS specification, so we
+ * silently skip it if it reads all zeroes.
+ */
+ if (midr == 0)
+ return;
+ print_cb(label,
+ "Implementor 0x%02x, Variant 0x%x, Architecture %u, Part 0x%03x, Revision %u",
+ midr >> 24, (midr >> 20) & 0xF,
+ (midr >> 16) & 0xF, (midr >> 4) & 0xFFF, midr & 0xF);
+ return;
+
+ case cpuid_arm_soc_id: /* ARM with SOC ID */
+ /*
+ * If Soc ID is supported, the first DWORD is the JEP-106 code;
+ * the second DWORD is the SoC revision value.
+ */
+ jep106 = DWORD(p);
+ soc_revision = DWORD(p + 4);
+ /*
+ * According to SMC Calling Convention (SMCCC) v1.3 specification
+ * (https://developer.arm.com/documentation/den0028/d/), the format
+ * of the values returned by the SMCCC_ARCH_SOC_ID call is as follows:
+ *
+ * JEP-106 code for the SiP (SoC_ID_type == 0)
+ * Bit[31] must be zero
+ * Bits[30:24] JEP-106 bank index for the SiP
+ * Bits[23:16] JEP-106 identification code with parity bit for the SiP
+ * Bits[15:0] Implementation defined SoC ID
+ *
+ * SoC revision (SoC_ID_type == 1)
+ * Bit[31] must be zero
+ * Bits[30:0] SoC revision
+ */
+ pr_attr("Signature",
+ "JEP-106 Bank 0x%02x Manufacturer 0x%02x, SoC ID 0x%04x, SoC Revision 0x%08x",
+ (jep106 >> 24) & 0x7F, (jep106 >> 16) & 0x7F, jep106 & 0xFFFF, soc_revision);
+ return;
+
+ case cpuid_x86_intel: /* Intel */
+ eax = DWORD(p);
+ /*
+ * Extra flags are now returned in the ECX register when
+ * one calls the CPUID instruction. Their meaning is
+ * explained in table 3-5, but DMI doesn't support this
+ * yet.
+ */
+ print_cb(label,
+ "Type %u, Family %u, Model %u, Stepping %u",
+ (eax >> 12) & 0x3,
+ ((eax >> 20) & 0xFF) + ((eax >> 8) & 0x0F),
+ ((eax >> 12) & 0xF0) + ((eax >> 4) & 0x0F),
+ eax & 0xF);
break;
- case 2: /* AMD, publication #25481 revision 2.28 */
- printf("%sSignature: Family %u, Model %u, Stepping %u\n",
- prefix,
- ((eax >> 8) & 0xF) + (((eax >> 8) & 0xF) == 0xF ? (eax >> 20) & 0xFF : 0),
- ((eax >> 4) & 0xF) | (((eax >> 8) & 0xF) == 0xF ? (eax >> 12) & 0xF0 : 0),
- eax & 0xF);
+
+ case cpuid_x86_amd: /* AMD, publication #25481 revision 2.28 */
+ eax = DWORD(p);
+ print_cb(label, "Family %u, Model %u, Stepping %u",
+ ((eax >> 8) & 0xF) + (((eax >> 8) & 0xF) == 0xF ? (eax >> 20) & 0xFF : 0),
+ ((eax >> 4) & 0xF) | (((eax >> 8) & 0xF) == 0xF ? (eax >> 12) & 0xF0 : 0),
+ eax & 0xF);
break;
+ default:
+ return;
}
+}
+
+static void dmi_processor_id(const struct dmi_header *h)
+{
+ /* Intel AP-485 revision 36, table 2-4 */
+ static const char *flags[32] = {
+ "FPU (Floating-point unit on-chip)", /* 0 */
+ "VME (Virtual mode extension)",
+ "DE (Debugging extension)",
+ "PSE (Page size extension)",
+ "TSC (Time stamp counter)",
+ "MSR (Model specific registers)",
+ "PAE (Physical address extension)",
+ "MCE (Machine check exception)",
+ "CX8 (CMPXCHG8 instruction supported)",
+ "APIC (On-chip APIC hardware supported)",
+ NULL, /* 10 */
+ "SEP (Fast system call)",
+ "MTRR (Memory type range registers)",
+ "PGE (Page global enable)",
+ "MCA (Machine check architecture)",
+ "CMOV (Conditional move instruction supported)",
+ "PAT (Page attribute table)",
+ "PSE-36 (36-bit page size extension)",
+ "PSN (Processor serial number present and enabled)",
+ "CLFSH (CLFLUSH instruction supported)",
+ NULL, /* 20 */
+ "DS (Debug store)",
+ "ACPI (ACPI supported)",
+ "MMX (MMX technology supported)",
+ "FXSR (FXSAVE and FXSTOR instructions supported)",
+ "SSE (Streaming SIMD extensions)",
+ "SSE2 (Streaming SIMD extensions 2)",
+ "SS (Self-snoop)",
+ "HTT (Multi-threading)",
+ "TM (Thermal monitor supported)",
+ NULL, /* 30 */
+ "PBE (Pending break enabled)" /* 31 */
+ };
+ const u8 *data = h->data;
+ const u8 *p = data + 0x08;
+ enum cpuid_type sig = dmi_get_cpuid_type(h);
+ u32 edx;
+
+ /*
+ * This might help learn about new processors supporting the
+ * CPUID instruction or another form of identification.
+ */
+ if (!(opt.flags & FLAG_QUIET))
+ pr_attr("ID", "%02X %02X %02X %02X %02X %02X %02X %02X",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+
+ dmi_print_cpuid(pr_attr, "Signature", sig, p);
+
+ if (sig != cpuid_x86_intel && sig != cpuid_x86_amd)
+ return;
edx = DWORD(p + 4);
- printf("%sFlags:", prefix);
if ((edx & 0xBFEFFBFF) == 0)
- printf(" None\n");
+ pr_list_start("Flags", "None");
else
{
int i;
- printf("\n");
+ pr_list_start("Flags", NULL);
for (i = 0; i <= 31; i++)
if (flags[i] != NULL && edx & (1 << i))
- printf("%s\t%s\n", prefix, flags[i]);
+ pr_list_item("%s", flags[i]);
}
+ pr_list_end();
}
-static void dmi_processor_voltage(u8 code)
+static void dmi_processor_voltage(const char *attr, u8 code)
{
/* 7.5.4 */
static const char *voltage[] = {
@@ -1172,25 +1289,47 @@ static void dmi_processor_voltage(u8 code)
int i;
if (code & 0x80)
- printf(" %.1f V", (float)(code & 0x7f) / 10);
+ pr_attr(attr, "%.1f V", (float)(code & 0x7f) / 10);
+ else if ((code & 0x07) == 0x00)
+ pr_attr(attr, "Unknown");
else
{
+ char voltage_str[18];
+ int off = 0;
+
for (i = 0; i <= 2; i++)
+ {
if (code & (1 << i))
- printf(" %s", voltage[i]);
- if (code == 0x00)
- printf(" Unknown");
+ {
+ /* Insert space if not the first value */
+ off += sprintf(voltage_str + off,
+ off ? " %s" :"%s",
+ voltage[i]);
+ }
+ }
+ if (off)
+ pr_attr(attr, voltage_str);
}
}
-static void dmi_processor_frequency(const u8 *p)
+static void dmi_processor_frequency(const char *attr, const u8 *p)
{
u16 code = WORD(p);
if (code)
- printf("%u MHz", code);
+ {
+ if (attr)
+ pr_attr(attr, "%u MHz", code);
+ else
+ printf("%u MHz\n", code);
+ }
else
- printf("Unknown");
+ {
+ if (attr)
+ pr_attr(attr, "Unknown");
+ else
+ printf("Unknown\n");
+ }
}
/* code is assumed to be a 3-bit value */
@@ -1269,28 +1408,36 @@ static const char *dmi_processor_upgrade(u8 code)
"Socket BGA1515",
"Socket LGA3647-1",
"Socket SP3",
- "Socket SP3r2" /* 0x38 */
+ "Socket SP3r2",
+ "Socket LGA2066",
+ "Socket BGA1392",
+ "Socket BGA1510",
+ "Socket BGA1528",
+ "Socket LGA4189",
+ "Socket LGA1200",
+ "Socket LGA4677" /* 0x3F */
};
- if (code >= 0x01 && code <= 0x38)
+ if (code >= 0x01 && code <= 0x3F)
return upgrade[code - 0x01];
return out_of_spec;
}
-static void dmi_processor_cache(u16 code, const char *level, u16 ver)
+static void dmi_processor_cache(const char *attr, u16 code, const char *level,
+ u16 ver)
{
if (code == 0xFFFF)
{
if (ver >= 0x0203)
- printf(" Not Provided");
+ pr_attr(attr, "Not Provided");
else
- printf(" No %s Cache", level);
+ pr_attr(attr, "No %s Cache", level);
}
else
- printf(" 0x%04X", code);
+ pr_attr(attr, "0x%04X", code);
}
-static void dmi_processor_characteristics(u16 code, const char *prefix)
+static void dmi_processor_characteristics(const char *attr, u16 code)
{
/* 7.5.9 */
static const char *characteristics[] = {
@@ -1299,19 +1446,22 @@ static void dmi_processor_characteristics(u16 code, const char *prefix)
"Hardware Thread",
"Execute Protection",
"Enhanced Virtualization",
- "Power/Performance Control" /* 7 */
+ "Power/Performance Control",
+ "128-bit Capable",
+ "Arm64 SoC ID" /* 9 */
};
if ((code & 0x00FC) == 0)
- printf(" None\n");
+ pr_attr(attr, "None");
else
{
int i;
- printf("\n");
- for (i = 2; i <= 7; i++)
+ pr_list_start(attr, NULL);
+ for (i = 2; i <= 9; i++)
if (code & (1 << i))
- printf("%s%s\n", prefix, characteristics[i - 2]);
+ pr_list_item("%s", characteristics[i - 2]);
+ pr_list_end();
}
}
@@ -1338,7 +1488,7 @@ static const char *dmi_memory_controller_ed_method(u8 code)
return out_of_spec;
}
-static void dmi_memory_controller_ec_capabilities(u8 code, const char *prefix)
+static void dmi_memory_controller_ec_capabilities(const char *attr, u8 code)
{
/* 7.6.2 */
static const char *capabilities[] = {
@@ -1351,15 +1501,16 @@ static void dmi_memory_controller_ec_capabilities(u8 code, const char *prefix)
};
if ((code & 0x3F) == 0)
- printf(" None\n");
+ pr_attr(attr, "None");
else
{
int i;
- printf("\n");
+ pr_list_start(attr, NULL);
for (i = 0; i <= 5; i++)
if (code & (1 << i))
- printf("%s%s\n", prefix, capabilities[i]);
+ pr_list_item("%s", capabilities[i]);
+ pr_list_end();
}
}
@@ -1381,7 +1532,7 @@ static const char *dmi_memory_controller_interleave(u8 code)
return out_of_spec;
}
-static void dmi_memory_controller_speeds(u16 code, const char *prefix)
+static void dmi_memory_controller_speeds(const char *attr, u16 code)
{
/* 7.6.4 */
const char *speeds[] = {
@@ -1393,34 +1544,34 @@ static void dmi_memory_controller_speeds(u16 code, const char *prefix)
};
if ((code & 0x001F) == 0)
- printf(" None\n");
+ pr_attr(attr, "None");
else
{
int i;
- printf("\n");
+ pr_list_start(attr, NULL);
for (i = 0; i <= 4; i++)
if (code & (1 << i))
- printf("%s%s\n", prefix, speeds[i]);
+ pr_list_item("%s", speeds[i]);
+ pr_list_end();
}
}
-static void dmi_memory_controller_slots(u8 count, const u8 *p, const char *prefix)
+static void dmi_memory_controller_slots(u8 count, const u8 *p)
{
int i;
- printf("%sAssociated Memory Slots: %u\n",
- prefix, count);
+ pr_list_start("Associated Memory Slots", "%u", count);
for (i = 0; i < count; i++)
- printf("%s\t0x%04X\n",
- prefix, WORD(p + sizeof(u16) * i));
+ pr_list_item("0x%04X", WORD(p + sizeof(u16) * i));
+ pr_list_end();
}
/*
* 7.7 Memory Module Information (Type 6)
*/
-static void dmi_memory_module_types(u16 code, const char *sep)
+static void dmi_memory_module_types(const char *attr, u16 code, int flat)
{
/* 7.7.1 */
static const char *types[] = {
@@ -1438,74 +1589,97 @@ static void dmi_memory_module_types(u16 code, const char *sep)
};
if ((code & 0x07FF) == 0)
- printf(" None");
+ pr_attr(attr, "None");
+ else if (flat)
+ {
+ char type_str[68];
+ int i, off = 0;
+
+ for (i = 0; i <= 10; i++)
+ {
+ if (code & (1 << i))
+ {
+ /* Insert space if not the first value */
+ off += sprintf(type_str + off,
+ off ? " %s" :"%s",
+ types[i]);
+ }
+ }
+ if (off)
+ pr_attr(attr, type_str);
+ }
else
{
int i;
+ pr_list_start(attr, NULL);
for (i = 0; i <= 10; i++)
if (code & (1 << i))
- printf("%s%s", sep, types[i]);
+ pr_list_item("%s", types[i]);
+ pr_list_end();
}
}
static void dmi_memory_module_connections(u8 code)
{
if (code == 0xFF)
- printf(" None");
+ pr_attr("Bank Connections", "None");
+ else if ((code & 0xF0) == 0xF0)
+ pr_attr("Bank Connections", "%u", code & 0x0F);
+ else if ((code & 0x0F) == 0x0F)
+ pr_attr("Bank Connections", "%u", code >> 4);
else
- {
- if ((code & 0xF0) != 0xF0)
- printf(" %u", code >> 4);
- if ((code & 0x0F) != 0x0F)
- printf(" %u", code & 0x0F);
- }
+ pr_attr("Bank Connections", "%u %u", code >> 4, code & 0x0F);
}
-static void dmi_memory_module_speed(u8 code)
+static void dmi_memory_module_speed(const char *attr, u8 code)
{
if (code == 0)
- printf(" Unknown");
+ pr_attr(attr, "Unknown");
else
- printf(" %u ns", code);
+ pr_attr(attr, "%u ns", code);
}
-static void dmi_memory_module_size(u8 code)
+static void dmi_memory_module_size(const char *attr, u8 code)
{
+ const char *connection;
+
/* 7.7.2 */
+ if (code & 0x80)
+ connection = " (Double-bank Connection)";
+ else
+ connection = " (Single-bank Connection)";
+
switch (code & 0x7F)
{
case 0x7D:
- printf(" Not Determinable");
+ pr_attr(attr, "Not Determinable%s", connection);
break;
case 0x7E:
- printf(" Disabled");
+ pr_attr(attr, "Disabled%s", connection);
break;
case 0x7F:
- printf(" Not Installed");
+ pr_attr(attr, "Not Installed");
return;
default:
- printf(" %u MB", 1 << (code & 0x7F));
+ pr_attr(attr, "%u MB%s", 1 << (code & 0x7F),
+ connection);
}
-
- if (code & 0x80)
- printf(" (Double-bank Connection)");
- else
- printf(" (Single-bank Connection)");
}
-static void dmi_memory_module_error(u8 code, const char *prefix)
+static void dmi_memory_module_error(u8 code)
{
+ static const char *status[] = {
+ "OK", /* 0x00 */
+ "Uncorrectable Errors",
+ "Correctable Errors",
+ "Correctable and Uncorrectable Errors" /* 0x03 */
+ };
+
if (code & (1 << 2))
- printf(" See Event Log\n");
+ pr_attr("Error Status", "See Event Log");
else
- { if ((code & 0x03) == 0)
- printf(" OK\n");
- if (code & (1 << 0))
- printf("%sUncorrectable Errors\n", prefix);
- if (code & (1 << 1))
- printf("%sCorrectable Errors\n", prefix);
- }
+ pr_attr("Error Status", "%s", status[code & 0x03]);
}
/*
@@ -1537,30 +1711,33 @@ static const char *dmi_cache_location(u8 code)
return location[code];
}
-static void dmi_cache_size(u16 code)
+static void dmi_cache_size_2(const char *attr, u32 code)
{
- if (code & 0x8000)
- printf(" %u kB", (code & 0x7FFF) << 6);
- else
- printf(" %u kB", code);
-}
+ u64 size;
-static void dmi_cache_size_2(u32 code)
-{
if (code & 0x80000000)
{
code &= 0x7FFFFFFFLU;
- /* Use a more convenient unit for large cache size */
- if (code >= 0x8000)
- printf(" %u MB", code >> 4);
- else
- printf(" %u kB", code << 6);
+ size.l = code << 6;
+ size.h = code >> 26;
}
else
- printf(" %u kB", code);
+ {
+ size.l = code;
+ size.h = 0;
+ }
+
+ /* Use a more convenient unit for large cache size */
+ dmi_print_memory_size(attr, size, 1);
}
-static void dmi_cache_types(u16 code, const char *sep)
+static void dmi_cache_size(const char *attr, u16 code)
+{
+ dmi_cache_size_2(attr,
+ (((u32)code & 0x8000LU) << 16) | (code & 0x7FFFLU));
+}
+
+static void dmi_cache_types(const char *attr, u16 code, int flat)
{
/* 7.8.2 */
static const char *types[] = {
@@ -1574,14 +1751,34 @@ static void dmi_cache_types(u16 code, const char *sep)
};
if ((code & 0x007F) == 0)
- printf(" None");
+ pr_attr(attr, "None");
+ else if (flat)
+ {
+ char type_str[70];
+ int i, off = 0;
+
+ for (i = 0; i <= 6; i++)
+ {
+ if (code & (1 << i))
+ {
+ /* Insert space if not the first value */
+ off += sprintf(type_str + off,
+ off ? " %s" :"%s",
+ types[i]);
+ }
+ }
+ if (off)
+ pr_attr(attr, type_str);
+ }
else
{
int i;
+ pr_list_start(attr, NULL);
for (i = 0; i <= 6; i++)
if (code & (1 << i))
- printf("%s%s", sep, types[i]);
+ pr_list_item("%s", types[i]);
+ pr_list_end();
}
}
@@ -1685,7 +1882,8 @@ static const char *dmi_port_connector_type(u8 code)
"Mini Jack (headphones)",
"BNC",
"IEEE 1394",
- "SAS/SATA Plug Receptacle" /* 0x22 */
+ "SAS/SATA Plug Receptacle",
+ "USB Type-C Receptacle" /* 0x23 */
};
static const char *type_0xA0[] = {
"PC-98", /* 0xA0 */
@@ -1695,7 +1893,7 @@ static const char *dmi_port_connector_type(u8 code)
"PC-98 Full" /* 0xA4 */
};
- if (code <= 0x22)
+ if (code <= 0x23)
return type[code];
if (code >= 0xA0 && code <= 0xA4)
return type_0xA0[code - 0xA0];
@@ -1795,11 +1993,19 @@ static const char *dmi_slot_type(u8 code)
"MXM Type IV",
"MXM 3.0 Type A",
"MXM 3.0 Type B",
- "PCI Express 2 SFF-8639",
- "PCI Express 3 SFF-8639",
+ "PCI Express 2 SFF-8639 (U.2)",
+ "PCI Express 3 SFF-8639 (U.2)",
"PCI Express Mini 52-pin with bottom-side keep-outs",
"PCI Express Mini 52-pin without bottom-side keep-outs",
- "PCI Express Mini 76-pin" /* 0x23 */
+ "PCI Express Mini 76-pin",
+ "PCI Express 4 SFF-8639 (U.2)",
+ "PCI Express 5 SFF-8639 (U.2)",
+ "OCP NIC 3.0 Small Form Factor (SFF)",
+ "OCP NIC 3.0 Large Form Factor (LFF)",
+ "OCP NIC Prior to 3.0" /* 0x28 */
+ };
+ static const char *type_0x30[] = {
+ "CXL FLexbus 1.0" /* 0x30 */
};
static const char *type_0xA0[] = {
"PC-98/C20", /* 0xA0 */
@@ -1824,45 +2030,81 @@ static const char *dmi_slot_type(u8 code)
"PCI Express 3 x2",
"PCI Express 3 x4",
"PCI Express 3 x8",
- "PCI Express 3 x16" /* 0xB6 */
+ "PCI Express 3 x16",
+ out_of_spec, /* 0xB7 */
+ "PCI Express 4",
+ "PCI Express 4 x1",
+ "PCI Express 4 x2",
+ "PCI Express 4 x4",
+ "PCI Express 4 x8",
+ "PCI Express 4 x16",
+ "PCI Express 5",
+ "PCI Express 5 x1",
+ "PCI Express 5 x2",
+ "PCI Express 5 x4",
+ "PCI Express 5 x8",
+ "PCI Express 5 x16",
+ "PCI Express 6+",
+ "EDSFF E1",
+ "EDSFF E3" /* 0xC6 */
};
/*
* Note to developers: when adding entries to these lists, check if
* function dmi_slot_id below needs updating too.
*/
- if (code >= 0x01 && code <= 0x23)
+ if (code >= 0x01 && code <= 0x28)
return type[code - 0x01];
- if (code >= 0xA0 && code <= 0xB6)
+ if (code == 0x30)
+ return type_0x30[code - 0x30];
+ if (code >= 0xA0 && code <= 0xC6)
return type_0xA0[code - 0xA0];
return out_of_spec;
}
-static const char *dmi_slot_bus_width(u8 code)
+/* If hide_unknown is set, return NULL instead of "Other" or "Unknown" */
+static const char *dmi_slot_bus_width(u8 code, int hide_unknown)
{
/* 7.10.2 */
static const char *width[] = {
- "", /* 0x01, "Other" */
- "", /* "Unknown" */
- "8-bit ",
- "16-bit ",
- "32-bit ",
- "64-bit ",
- "128-bit ",
- "x1 ",
- "x2 ",
- "x4 ",
- "x8 ",
- "x12 ",
- "x16 ",
- "x32 " /* 0x0E */
+ "Other", /* 0x01 */
+ "Unknown",
+ "8-bit",
+ "16-bit",
+ "32-bit",
+ "64-bit",
+ "128-bit",
+ "x1",
+ "x2",
+ "x4",
+ "x8",
+ "x12",
+ "x16",
+ "x32" /* 0x0E */
};
if (code >= 0x01 && code <= 0x0E)
+ {
+ if (code <= 0x02 && hide_unknown)
+ return NULL;
return width[code - 0x01];
+ }
return out_of_spec;
}
+static void dmi_slot_type_with_width(u8 type, u8 width)
+{
+ const char *type_str, *width_str;
+
+ type_str = dmi_slot_type(type);
+ width_str = dmi_slot_bus_width(width, 1);
+
+ if (width_str)
+ pr_attr("Type", "%s %s", width_str, type_str);
+ else
+ pr_attr("Type", "%s", type_str);
+}
+
static const char *dmi_slot_current_usage(u8 code)
{
/* 7.10.3 */
@@ -1870,39 +2112,42 @@ static const char *dmi_slot_current_usage(u8 code)
"Other", /* 0x01 */
"Unknown",
"Available",
- "In Use" /* 0x04 */
+ "In Use",
+ "Unavailable" /* 0x05 */
};
- if (code >= 0x01 && code <= 0x04)
+ if (code >= 0x01 && code <= 0x05)
return usage[code - 0x01];
return out_of_spec;
}
static const char *dmi_slot_length(u8 code)
{
- /* 7.1O.4 */
+ /* 7.10.4 */
static const char *length[] = {
"Other", /* 0x01 */
"Unknown",
"Short",
- "Long" /* 0x04 */
+ "Long",
+ "2.5\" drive form factor",
+ "3.5\" drive form factor" /* 0x06 */
};
- if (code >= 0x01 && code <= 0x04)
+ if (code >= 0x01 && code <= 0x06)
return length[code - 0x01];
return out_of_spec;
}
-static void dmi_slot_id(u8 code1, u8 code2, u8 type, const char *prefix)
+static void dmi_slot_id(u8 code1, u8 code2, u8 type)
{
/* 7.10.5 */
switch (type)
{
case 0x04: /* MCA */
- printf("%sID: %u\n", prefix, code1);
+ pr_attr("ID", "%u", code1);
break;
case 0x05: /* EISA */
- printf("%sID: %u\n", prefix, code1);
+ pr_attr("ID", "%u", code1);
break;
case 0x06: /* PCI */
case 0x0E: /* PCI */
@@ -1934,15 +2179,28 @@ static void dmi_slot_id(u8 code1, u8 code2, u8 type, const char *prefix)
case 0xB4: /* PCI Express 3 */
case 0xB5: /* PCI Express 3 */
case 0xB6: /* PCI Express 3 */
- printf("%sID: %u\n", prefix, code1);
+ case 0xB8: /* PCI Express 4 */
+ case 0xB9: /* PCI Express 4 */
+ case 0xBA: /* PCI Express 4 */
+ case 0xBB: /* PCI Express 4 */
+ case 0xBC: /* PCI Express 4 */
+ case 0xBD: /* PCI Express 4 */
+ case 0xBE: /* PCI Express 5 */
+ case 0xBF: /* PCI Express 5 */
+ case 0xC0: /* PCI Express 5 */
+ case 0xC1: /* PCI Express 5 */
+ case 0xC2: /* PCI Express 5 */
+ case 0xC3: /* PCI Express 5 */
+ case 0xC4: /* PCI Express 6+ */
+ pr_attr("ID", "%u", code1);
break;
case 0x07: /* PCMCIA */
- printf("%sID: Adapter %u, Socket %u\n", prefix, code1, code2);
+ pr_attr("ID", "Adapter %u, Socket %u", code1, code2);
break;
}
}
-static void dmi_slot_characteristics(u8 code1, u8 code2, const char *prefix)
+static void dmi_slot_characteristics(const char *attr, u8 code1, u8 code2)
{
/* 7.10.6 */
static const char *characteristics1[] = {
@@ -1958,33 +2216,127 @@ static void dmi_slot_characteristics(u8 code1, u8 code2, const char *prefix)
static const char *characteristics2[] = {
"PME signal is supported", /* 0 */
"Hot-plug devices are supported",
- "SMBus signal is supported" /* 2 */
+ "SMBus signal is supported",
+ "PCIe slot bifurcation is supported",
+ "Async/surprise removal is supported",
+ "Flexbus slot, CXL 1.0 capable",
+ "Flexbus slot, CXL 2.0 capable" /* 6 */
};
if (code1 & (1 << 0))
- printf(" Unknown\n");
+ pr_attr(attr, "Unknown");
else if ((code1 & 0xFE) == 0 && (code2 & 0x07) == 0)
- printf(" None\n");
+ pr_attr(attr, "None");
else
{
int i;
- printf("\n");
+ pr_list_start(attr, NULL);
for (i = 1; i <= 7; i++)
if (code1 & (1 << i))
- printf("%s%s\n", prefix, characteristics1[i - 1]);
- for (i = 0; i <= 2; i++)
+ pr_list_item("%s", characteristics1[i - 1]);
+ for (i = 0; i <= 6; i++)
if (code2 & (1 << i))
- printf("%s%s\n", prefix, characteristics2[i]);
+ pr_list_item("%s", characteristics2[i]);
+ pr_list_end();
}
}
-static void dmi_slot_segment_bus_func(u16 code1, u8 code2, u8 code3, const char *prefix)
+static void dmi_slot_segment_bus_func(u16 code1, u8 code2, u8 code3)
{
/* 7.10.8 */
if (!(code1 == 0xFFFF && code2 == 0xFF && code3 == 0xFF))
- printf("%sBus Address: %04x:%02x:%02x.%x\n",
- prefix, code1, code2, code3 >> 3, code3 & 0x7);
+ pr_attr("Bus Address", "%04x:%02x:%02x.%x",
+ code1, code2, code3 >> 3, code3 & 0x7);
+}
+
+static void dmi_slot_peers(u8 n, const u8 *data)
+{
+ char attr[16];
+ int i;
+
+ for (i = 1; i <= n; i++, data += 5)
+ {
+ sprintf(attr, "Peer Device %hhu", (u8)i);
+ pr_attr(attr, "%04x:%02x:%02x.%x (Width %u)",
+ WORD(data), data[2], data[3] >> 3, data[3] & 0x07,
+ data[4]);
+ }
+}
+
+static void dmi_slot_information(u8 type, u8 code)
+{
+ switch (type)
+ {
+ case 0x1F: /* PCI Express 2 */
+ case 0x20: /* PCI Express 3 */
+ case 0x21: /* PCI Express Mini */
+ case 0x22: /* PCI Express Mini */
+ case 0x23: /* PCI Express Mini */
+ case 0xA5: /* PCI Express */
+ case 0xA6: /* PCI Express */
+ case 0xA7: /* PCI Express */
+ case 0xA8: /* PCI Express */
+ case 0xA9: /* PCI Express */
+ case 0xAA: /* PCI Express */
+ case 0xAB: /* PCI Express 2 */
+ case 0xAC: /* PCI Express 2 */
+ case 0xAD: /* PCI Express 2 */
+ case 0xAE: /* PCI Express 2 */
+ case 0xAF: /* PCI Express 2 */
+ case 0xB0: /* PCI Express 2 */
+ case 0xB1: /* PCI Express 3 */
+ case 0xB2: /* PCI Express 3 */
+ case 0xB3: /* PCI Express 3 */
+ case 0xB4: /* PCI Express 3 */
+ case 0xB5: /* PCI Express 3 */
+ case 0xB6: /* PCI Express 3 */
+ case 0xB8: /* PCI Express 4 */
+ case 0xB9: /* PCI Express 4 */
+ case 0xBA: /* PCI Express 4 */
+ case 0xBB: /* PCI Express 4 */
+ case 0xBC: /* PCI Express 4 */
+ case 0xBD: /* PCI Express 4 */
+ case 0xBE: /* PCI Express 5 */
+ case 0xBF: /* PCI Express 5 */
+ case 0xC0: /* PCI Express 5 */
+ case 0xC1: /* PCI Express 5 */
+ case 0xC2: /* PCI Express 5 */
+ case 0xC3: /* PCI Express 5 */
+ case 0xC4: /* PCI Express 6+ */
+ if (code)
+ pr_attr("PCI Express Generation", "%u", code);
+ break;
+ }
+}
+
+static void dmi_slot_physical_width(u8 code)
+{
+ if (code)
+ pr_attr("Slot Physical Width", "%s",
+ dmi_slot_bus_width(code, 0));
+}
+
+static void dmi_slot_pitch(u16 code)
+{
+ if (code)
+ pr_attr("Pitch", "%u.%02u mm", code / 100, code % 100);
+}
+
+static const char *dmi_slot_height(u8 code)
+{
+ /* 7.10.3 */
+ static const char *height[] = {
+ "Not applicable", /* 0x00 */
+ "Other",
+ "Unknown",
+ "Full height",
+ "Low-profile" /* 0x04 */
+ };
+
+ if (code <= 0x04)
+ return height[code];
+ return out_of_spec;
}
/*
@@ -2004,15 +2356,21 @@ static const char *dmi_on_board_devices_type(u8 code)
"Sound",
"PATA Controller",
"SATA Controller",
- "SAS Controller" /* 0x0A */
+ "SAS Controller",
+ "Wireless LAN",
+ "Bluetooth",
+ "WWAN",
+ "eMMC",
+ "NVMe Controller",
+ "UFS Controller" /* 0x10 */
};
- if (code >= 0x01 && code <= 0x0A)
+ if (code >= 0x01 && code <= 0x10)
return type[code - 0x01];
return out_of_spec;
}
-static void dmi_on_board_devices(const struct dmi_header *h, const char *prefix)
+static void dmi_on_board_devices(const struct dmi_header *h)
{
u8 *p = h->data + 4;
u8 count = (h->length - 0x04) / 2;
@@ -2021,17 +2379,15 @@ static void dmi_on_board_devices(const struct dmi_header *h, const char *prefix)
for (i = 0; i < count; i++)
{
if (count == 1)
- printf("%sOn Board Device Information\n",
- prefix);
+ pr_handle_name("On Board Device Information");
else
- printf("%sOn Board Device %d Information\n",
- prefix, i + 1);
- printf("%s\tType: %s\n",
- prefix, dmi_on_board_devices_type(p[2 * i] & 0x7F));
- printf("%s\tStatus: %s\n",
- prefix, p[2 * i] & 0x80 ? "Enabled" : "Disabled");
- printf("%s\tDescription: %s\n",
- prefix, dmi_string(h, p[2 * i + 1]));
+ pr_handle_name("On Board Device %d Information",
+ i + 1);
+ pr_attr("Type", "%s",
+ dmi_on_board_devices_type(p[2 * i] & 0x7F));
+ pr_attr("Status", "%s",
+ p[2 * i] & 0x80 ? "Enabled" : "Disabled");
+ pr_attr("Description", "%s", dmi_string(h, p[2 * i + 1]));
}
}
@@ -2039,45 +2395,50 @@ static void dmi_on_board_devices(const struct dmi_header *h, const char *prefix)
* 7.12 OEM Strings (Type 11)
*/
-static void dmi_oem_strings(const struct dmi_header *h, const char *prefix)
+static void dmi_oem_strings(const struct dmi_header *h)
{
+ char attr[11];
u8 *p = h->data + 4;
u8 count = p[0x00];
int i;
for (i = 1; i <= count; i++)
- printf("%sString %d: %s\n",
- prefix, i, dmi_string(h, i));
+ {
+ sprintf(attr, "String %hhu", (u8)i);
+ pr_attr(attr, "%s",dmi_string(h, i));
+ }
}
/*
* 7.13 System Configuration Options (Type 12)
*/
-static void dmi_system_configuration_options(const struct dmi_header *h, const char *prefix)
+static void dmi_system_configuration_options(const struct dmi_header *h)
{
+ char attr[11];
u8 *p = h->data + 4;
u8 count = p[0x00];
int i;
for (i = 1; i <= count; i++)
- printf("%sOption %d: %s\n",
- prefix, i, dmi_string(h, i));
+ {
+ sprintf(attr, "Option %hhu", (u8)i);
+ pr_attr(attr, "%s",dmi_string(h, i));
+ }
}
/*
* 7.14 BIOS Language Information (Type 13)
*/
-static void dmi_bios_languages(const struct dmi_header *h, const char *prefix)
+static void dmi_bios_languages(const struct dmi_header *h)
{
u8 *p = h->data + 4;
u8 count = p[0x00];
int i;
for (i = 1; i <= count; i++)
- printf("%s%s\n",
- prefix, dmi_string(h, i));
+ pr_list_item("%s", dmi_string(h, i));
}
static const char *dmi_bios_language_format(u8 code)
@@ -2092,14 +2453,14 @@ static const char *dmi_bios_language_format(u8 code)
* 7.15 Group Associations (Type 14)
*/
-static void dmi_group_associations_items(u8 count, const u8 *p, const char *prefix)
+static void dmi_group_associations_items(u8 count, const u8 *p)
{
int i;
for (i = 0; i < count; i++)
{
- printf("%s0x%04X (%s)\n",
- prefix, WORD(p + 3 * i + 1),
+ pr_list_item("0x%04X (%s)",
+ WORD(p + 3 * i + 1),
dmi_smbios_structure_type(p[3 * i]));
}
}
@@ -2136,7 +2497,7 @@ static void dmi_event_log_status(u8 code)
"Full" /* 1 */
};
- printf(" %s, %s",
+ pr_attr("Status", "%s, %s",
valid[(code >> 0) & 1], full[(code >> 1) & 1]);
}
@@ -2148,16 +2509,17 @@ static void dmi_event_log_address(u8 method, const u8 *p)
case 0x00:
case 0x01:
case 0x02:
- printf(" Index 0x%04X, Data 0x%04X", WORD(p), WORD(p + 2));
+ pr_attr("Access Address", "Index 0x%04X, Data 0x%04X",
+ WORD(p), WORD(p + 2));
break;
case 0x03:
- printf(" 0x%08X", DWORD(p));
+ pr_attr("Access Address", "0x%08X", DWORD(p));
break;
case 0x04:
- printf(" 0x%04X", WORD(p));
+ pr_attr("Access Address", "0x%04X", WORD(p));
break;
default:
- printf(" Unknown");
+ pr_attr("Access Address", "Unknown");
}
}
@@ -2234,19 +2596,22 @@ static const char *dmi_event_log_descriptor_format(u8 code)
return out_of_spec;
}
-static void dmi_event_log_descriptors(u8 count, u8 len, const u8 *p, const char *prefix)
+static void dmi_event_log_descriptors(u8 count, u8 len, const u8 *p)
{
/* 7.16.1 */
+ char attr[16];
int i;
for (i = 0; i < count; i++)
{
if (len >= 0x02)
{
- printf("%sDescriptor %u: %s\n",
- prefix, i + 1, dmi_event_log_descriptor_type(p[i * len]));
- printf("%sData Format %u: %s\n",
- prefix, i + 1, dmi_event_log_descriptor_format(p[i * len + 1]));
+ sprintf(attr, "Descriptor %d", i + 1);
+ pr_attr(attr, "%s",
+ dmi_event_log_descriptor_type(p[i * len]));
+ sprintf(attr, "Data Format %d", i + 1);
+ pr_attr(attr, "%s",
+ dmi_event_log_descriptor_format(p[i * len + 1]));
}
}
}
@@ -2274,12 +2639,13 @@ static const char *dmi_memory_array_location(u8 code)
"PC-98/C20 Add-on Card", /* 0xA0 */
"PC-98/C24 Add-on Card",
"PC-98/E Add-on Card",
- "PC-98/Local Bus Add-on Card" /* 0xA3 */
+ "PC-98/Local Bus Add-on Card",
+ "CXL Flexbus 1.0" /* 0xA4 */
};
if (code >= 0x01 && code <= 0x0A)
return location[code - 0x01];
- if (code >= 0xA0 && code <= 0xA3)
+ if (code >= 0xA0 && code <= 0xA4)
return location_0xA0[code - 0xA0];
return out_of_spec;
}
@@ -2323,40 +2689,40 @@ static const char *dmi_memory_array_ec_type(u8 code)
static void dmi_memory_array_error_handle(u16 code)
{
if (code == 0xFFFE)
- printf(" Not Provided");
+ pr_attr("Error Information Handle", "Not Provided");
else if (code == 0xFFFF)
- printf(" No Error");
+ pr_attr("Error Information Handle", "No Error");
else
- printf(" 0x%04X", code);
+ pr_attr("Error Information Handle", "0x%04X", code);
}
/*
* 7.18 Memory Device (Type 17)
*/
-static void dmi_memory_device_width(u16 code)
+static void dmi_memory_device_width(const char *attr, u16 code)
{
/*
* If no memory module is present, width may be 0
*/
- if (code == 0xFFFF || code == 0)
- printf(" Unknown");
+ if (code == 0xFFFF || (code == 0 && !(opt.flags & FLAG_NO_QUIRKS)))
+ pr_attr(attr, "Unknown");
else
- printf(" %u bits", code);
+ pr_attr(attr, "%u bits", code);
}
static void dmi_memory_device_size(u16 code)
{
if (code == 0)
- printf(" No Module Installed");
+ pr_attr("Size", "No Module Installed");
else if (code == 0xFFFF)
- printf(" Unknown");
+ pr_attr("Size", "Unknown");
else
{
- if (code & 0x8000)
- printf(" %u kB", code & 0x7FFF);
- else
- printf(" %u MB", code);
+ u64 s = { .l = code & 0x7FFF };
+ if (!(code & 0x8000))
+ s.l <<= 10;
+ dmi_print_memory_size("Size", s, 1);
}
}
@@ -2369,19 +2735,20 @@ static void dmi_memory_device_extended_size(u32 code)
* as an integer without rounding
*/
if (code & 0x3FFUL)
- printf(" %lu MB", (unsigned long)code);
+ pr_attr("Size", "%lu MB", (unsigned long)code);
else if (code & 0xFFC00UL)
- printf(" %lu GB", (unsigned long)code >> 10);
+ pr_attr("Size", "%lu GB", (unsigned long)code >> 10);
else
- printf(" %lu TB", (unsigned long)code >> 20);
+ pr_attr("Size", "%lu TB", (unsigned long)code >> 20);
}
-static void dmi_memory_voltage_value(u16 code)
+static void dmi_memory_voltage_value(const char *attr, u16 code)
{
if (code == 0)
- printf(" Unknown");
+ pr_attr(attr, "Unknown");
else
- printf(code % 100 ? " %g V" : " %.1f V", (float)code / 1000);
+ pr_attr(attr, code % 100 ? "%g V" : "%.1f V",
+ (float)code / 1000);
}
static const char *dmi_memory_device_form_factor(u8 code)
@@ -2402,10 +2769,11 @@ static const char *dmi_memory_device_form_factor(u8 code)
"RIMM",
"SODIMM",
"SRIMM",
- "FB-DIMM" /* 0x0F */
+ "FB-DIMM",
+ "Die" /* 0x10 */
};
- if (code >= 0x01 && code <= 0x0F)
+ if (code >= 0x01 && code <= 0x10)
return form_factor[code - 0x01];
return out_of_spec;
}
@@ -2413,11 +2781,11 @@ static const char *dmi_memory_device_form_factor(u8 code)
static void dmi_memory_device_set(u8 code)
{
if (code == 0)
- printf(" None");
+ pr_attr("Set", "None");
else if (code == 0xFF)
- printf(" Unknown");
+ pr_attr("Set", "Unknown");
else
- printf(" %u", code);
+ pr_attr("Set", "%u", code);
}
static const char *dmi_memory_device_type(u8 code)
@@ -2453,10 +2821,15 @@ static const char *dmi_memory_device_type(u8 code)
"LPDDR",
"LPDDR2",
"LPDDR3",
- "LPDDR4" /* 0x1E */
+ "LPDDR4",
+ "Logical non-volatile device",
+ "HBM",
+ "HBM2",
+ "DDR5",
+ "LPDDR5" /* 0x23 */
};
- if (code >= 0x01 && code <= 0x1E)
+ if (code >= 0x01 && code <= 0x23)
return type[code - 0x01];
return out_of_spec;
}
@@ -2481,25 +2854,117 @@ static void dmi_memory_device_type_detail(u16 code)
"Unbuffered (Unregistered)",
"LRDIMM" /* 15 */
};
+ char list[172]; /* Update length if you touch the array above */
if ((code & 0xFFFE) == 0)
- printf(" None");
+ pr_attr("Type Detail", "None");
else
{
- int i;
+ int i, off = 0;
+ list[0] = '\0';
for (i = 1; i <= 15; i++)
if (code & (1 << i))
- printf(" %s", detail[i - 1]);
+ off += sprintf(list + off, off ? " %s" : "%s",
+ detail[i - 1]);
+ pr_attr("Type Detail", list);
}
}
-static void dmi_memory_device_speed(u16 code)
+static void dmi_memory_device_speed(const char *attr, u16 code1, u32 code2)
{
+ if (code1 == 0xFFFF)
+ {
+ if (code2 == 0)
+ pr_attr(attr, "Unknown");
+ else
+ pr_attr(attr, "%lu MT/s", code2);
+ }
+ else
+ {
+ if (code1 == 0)
+ pr_attr(attr, "Unknown");
+ else
+ pr_attr(attr, "%u MT/s", code1);
+ }
+}
+
+static void dmi_memory_technology(u8 code)
+{
+ /* 7.18.6 */
+ static const char * const technology[] = {
+ "Other", /* 0x01 */
+ "Unknown",
+ "DRAM",
+ "NVDIMM-N",
+ "NVDIMM-F",
+ "NVDIMM-P",
+ "Intel Optane DC persistent memory" /* 0x07 */
+ };
+ if (code >= 0x01 && code <= 0x07)
+ pr_attr("Memory Technology", "%s", technology[code - 0x01]);
+ else
+ pr_attr("Memory Technology", "%s", out_of_spec);
+}
+
+static void dmi_memory_operating_mode_capability(u16 code)
+{
+ /* 7.18.7 */
+ static const char * const mode[] = {
+ "Other", /* 1 */
+ "Unknown",
+ "Volatile memory",
+ "Byte-accessible persistent memory",
+ "Block-accessible persistent memory" /* 5 */
+ };
+ char list[99]; /* Update length if you touch the array above */
+
+ if ((code & 0xFFFE) == 0)
+ pr_attr("Memory Operating Mode Capability", "None");
+ else {
+ int i, off = 0;
+
+ list[0] = '\0';
+ for (i = 1; i <= 5; i++)
+ if (code & (1 << i))
+ off += sprintf(list + off, off ? " %s" : "%s",
+ mode[i - 1]);
+ pr_attr("Memory Operating Mode Capability", list);
+ }
+}
+
+static void dmi_memory_manufacturer_id(const char *attr, u16 code)
+{
+ /* 7.18.8 */
+ /* 7.18.10 */
+ /* LSB is 7-bit Odd Parity number of continuation codes */
+ if (code == 0)
+ pr_attr(attr, "Unknown");
+ else
+ pr_attr(attr, "Bank %d, Hex 0x%02X",
+ (code & 0x7F) + 1, code >> 8);
+}
+
+static void dmi_memory_product_id(const char *attr, u16 code)
+{
+ /* 7.18.9 */
+ /* 7.18.11 */
if (code == 0)
- printf(" Unknown");
+ pr_attr(attr, "Unknown");
+ else
+ pr_attr(attr, "0x%04X", code);
+}
+
+static void dmi_memory_size(const char *attr, u64 code)
+{
+ /* 7.18.12 */
+ /* 7.18.13 */
+ if (code.h == 0xFFFFFFFF && code.l == 0xFFFFFFFF)
+ pr_attr(attr, "Unknown");
+ else if (code.h == 0x0 && code.l == 0x0)
+ pr_attr(attr, "None");
else
- printf(" %u MT/s", code);
+ dmi_print_memory_size(attr, code, 0);
}
/*
@@ -2565,17 +3030,17 @@ static const char *dmi_memory_error_operation(u8 code)
static void dmi_memory_error_syndrome(u32 code)
{
if (code == 0x00000000)
- printf(" Unknown");
+ pr_attr("Vendor Syndrome", "Unknown");
else
- printf(" 0x%08X", code);
+ pr_attr("Vendor Syndrome", "0x%08X", code);
}
-static void dmi_32bit_memory_error_address(u32 code)
+static void dmi_32bit_memory_error_address(const char *attr, u32 code)
{
if (code == 0x80000000)
- printf(" Unknown");
+ pr_attr(attr, "Unknown");
else
- printf(" 0x%08X", code);
+ pr_attr(attr, "0x%08X", code);
}
/*
@@ -2585,23 +3050,23 @@ static void dmi_32bit_memory_error_address(u32 code)
static void dmi_mapped_address_size(u32 code)
{
if (code == 0)
- printf(" Invalid");
+ pr_attr("Range Size", "Invalid");
else
{
u64 size;
size.h = 0;
size.l = code;
- dmi_print_memory_size(size, 1);
+ dmi_print_memory_size("Range Size", size, 1);
}
}
static void dmi_mapped_address_extended_size(u64 start, u64 end)
{
if (start.h == end.h && start.l == end.l)
- printf(" Invalid");
+ pr_attr("Range Size", "Invalid");
else
- dmi_print_memory_size(u64_range(start, end), 0);
+ dmi_print_memory_size("Range Size", u64_range(start, end), 0);
}
/*
@@ -2611,36 +3076,32 @@ static void dmi_mapped_address_extended_size(u64 start, u64 end)
static void dmi_mapped_address_row_position(u8 code)
{
if (code == 0)
- printf(" %s", out_of_spec);
+ pr_attr("Partition Row Position", "%s", out_of_spec);
else if (code == 0xFF)
- printf(" Unknown");
+ pr_attr("Partition Row Position", "Unknown");
else
- printf(" %u", code);
+ pr_attr("Partition Row Position", "%u", code);
}
-static void dmi_mapped_address_interleave_position(u8 code, const char *prefix)
+static void dmi_mapped_address_interleave_position(u8 code)
{
if (code != 0)
{
- printf("%sInterleave Position:", prefix);
if (code == 0xFF)
- printf(" Unknown");
+ pr_attr("Interleave Position", "Unknown");
else
- printf(" %u", code);
- printf("\n");
+ pr_attr("Interleave Position", "%u", code);
}
}
-static void dmi_mapped_address_interleaved_data_depth(u8 code, const char *prefix)
+static void dmi_mapped_address_interleaved_data_depth(u8 code)
{
if (code != 0)
{
- printf("%sInterleaved Data Depth:", prefix);
if (code == 0xFF)
- printf(" Unknown");
+ pr_attr("Interleaved Data Depth", "Unknown");
else
- printf(" %u", code);
- printf("\n");
+ pr_attr("Interleaved Data Depth", "%u", code);
}
}
@@ -2684,12 +3145,14 @@ static const char *dmi_pointing_device_interface(u8 code)
static const char *interface_0xA0[] = {
"Bus Mouse DB-9", /* 0xA0 */
"Bus Mouse Micro DIN",
- "USB" /* 0xA2 */
+ "USB",
+ "I2C",
+ "SPI" /* 0xA4 */
};
if (code >= 0x01 && code <= 0x08)
return interface[code - 0x01];
- if (code >= 0xA0 && code <= 0xA2)
+ if (code >= 0xA0 && code <= 0xA4)
return interface_0xA0[code - 0xA0];
return out_of_spec;
}
@@ -2720,25 +3183,25 @@ static const char *dmi_battery_chemistry(u8 code)
static void dmi_battery_capacity(u16 code, u8 multiplier)
{
if (code == 0)
- printf(" Unknown");
+ pr_attr("Design Capacity", "Unknown");
else
- printf(" %u mWh", code * multiplier);
+ pr_attr("Design Capacity", "%u mWh", code * multiplier);
}
static void dmi_battery_voltage(u16 code)
{
if (code == 0)
- printf(" Unknown");
+ pr_attr("Design Voltage", "Unknown");
else
- printf(" %u mV", code);
+ pr_attr("Design Voltage", "%u mV", code);
}
static void dmi_battery_maximum_error(u8 code)
{
if (code == 0xFF)
- printf(" Unknown");
+ pr_attr("Maximum Error", "Unknown");
else
- printf(" %u%%", code);
+ pr_attr("Maximum Error", "%u%%", code);
}
/*
@@ -2758,20 +3221,20 @@ static const char *dmi_system_reset_boot_option(u8 code)
return option[code];
}
-static void dmi_system_reset_count(u16 code)
+static void dmi_system_reset_count(const char *attr, u16 code)
{
if (code == 0xFFFF)
- printf(" Unknown");
+ pr_attr(attr, "Unknown");
else
- printf(" %u", code);
+ pr_attr(attr, "%u", code);
}
-static void dmi_system_reset_timer(u16 code)
+static void dmi_system_reset_timer(const char *attr, u16 code)
{
if (code == 0xFFFF)
- printf(" Unknown");
+ pr_attr(attr, "Unknown");
else
- printf(" %u min", code);
+ pr_attr(attr, "%u min", code);
}
/*
@@ -2796,27 +3259,32 @@ static const char *dmi_hardware_security_status(u8 code)
static void dmi_power_controls_power_on(const u8 *p)
{
+ char time[15];
+ int off = 0;
+
/* 7.26.1 */
if (dmi_bcd_range(p[0], 0x01, 0x12))
- printf(" %02X", p[0]);
+ off += sprintf(time + off, "%02X", p[0]);
else
- printf(" *");
+ off += sprintf(time + off, "*");
if (dmi_bcd_range(p[1], 0x01, 0x31))
- printf("-%02X", p[1]);
+ off += sprintf(time + off, "-%02X", p[1]);
else
- printf("-*");
+ off += sprintf(time + off, "-*");
if (dmi_bcd_range(p[2], 0x00, 0x23))
- printf(" %02X", p[2]);
+ off += sprintf(time + off, " %02X", p[2]);
else
- printf(" *");
+ off += sprintf(time + off, " *");
if (dmi_bcd_range(p[3], 0x00, 0x59))
- printf(":%02X", p[3]);
+ off += sprintf(time + off, ":%02X", p[3]);
else
- printf(":*");
+ off += sprintf(time + off, ":*");
if (dmi_bcd_range(p[4], 0x00, 0x59))
- printf(":%02X", p[4]);
+ off += sprintf(time + off, ":%02X", p[4]);
else
- printf(":*");
+ off += sprintf(time + off, ":*");
+
+ pr_attr("Next Scheduled Power-on", time);
}
/*
@@ -2862,28 +3330,28 @@ static const char *dmi_probe_status(u8 code)
return out_of_spec;
}
-static void dmi_voltage_probe_value(u16 code)
+static void dmi_voltage_probe_value(const char *attr, u16 code)
{
if (code == 0x8000)
- printf(" Unknown");
+ pr_attr(attr, "Unknown");
else
- printf(" %.3f V", (float)(i16)code / 1000);
+ pr_attr(attr, "%.3f V", (float)(i16)code / 1000);
}
static void dmi_voltage_probe_resolution(u16 code)
{
if (code == 0x8000)
- printf(" Unknown");
+ pr_attr("Resolution", "Unknown");
else
- printf(" %.1f mV", (float)code / 10);
+ pr_attr("Resolution", "%.1f mV", (float)code / 10);
}
static void dmi_probe_accuracy(u16 code)
{
if (code == 0x8000)
- printf(" Unknown");
+ pr_attr("Accuracy", "Unknown");
else
- printf(" %.2f%%", (float)code / 100);
+ pr_attr("Accuracy", "%.2f%%", (float)code / 100);
}
/*
@@ -2919,9 +3387,9 @@ static const char *dmi_cooling_device_type(u8 code)
static void dmi_cooling_device_speed(u16 code)
{
if (code == 0x8000)
- printf(" Unknown Or Non-rotating");
+ pr_attr("Nominal Speed", "Unknown Or Non-rotating");
else
- printf(" %u rpm", code);
+ pr_attr("Nominal Speed", "%u rpm", code);
}
/*
@@ -2954,40 +3422,40 @@ static const char *dmi_temperature_probe_location(u8 code)
return out_of_spec;
}
-static void dmi_temperature_probe_value(u16 code)
+static void dmi_temperature_probe_value(const char *attr, u16 code)
{
if (code == 0x8000)
- printf(" Unknown");
+ pr_attr(attr, "Unknown");
else
- printf(" %.1f deg C", (float)(i16)code / 10);
+ pr_attr(attr, "%.1f deg C", (float)(i16)code / 10);
}
static void dmi_temperature_probe_resolution(u16 code)
{
if (code == 0x8000)
- printf(" Unknown");
+ pr_attr("Resolution", "Unknown");
else
- printf(" %.3f deg C", (float)code / 1000);
+ pr_attr("Resolution", "%.3f deg C", (float)code / 1000);
}
/*
* 7.30 Electrical Current Probe (Type 29)
*/
-static void dmi_current_probe_value(u16 code)
+static void dmi_current_probe_value(const char *attr, u16 code)
{
if (code == 0x8000)
- printf(" Unknown");
+ pr_attr(attr, "Unknown");
else
- printf(" %.3f A", (float)(i16)code / 1000);
+ pr_attr(attr, "%.3f A", (float)(i16)code / 1000);
}
static void dmi_current_probe_resolution(u16 code)
{
if (code == 0x8000)
- printf(" Unknown");
+ pr_attr("Resolution", "Unknown");
else
- printf(" %.1f mA", (float)code / 10);
+ pr_attr("Resolution", "%.1f mA", (float)code / 10);
}
/*
@@ -3021,12 +3489,12 @@ static const char *dmi_system_boot_status(u8 code)
* 7.34 64-bit Memory Error Information (Type 33)
*/
-static void dmi_64bit_memory_error_address(u64 code)
+static void dmi_64bit_memory_error_address(const char *attr, u64 code)
{
if (code.h == 0x80000000 && code.l == 0x00000000)
- printf(" Unknown");
+ pr_attr(attr, "Unknown");
else
- printf(" 0x%08X%08X", code.h, code.l);
+ pr_attr(attr, "0x%08X%08X", code.h, code.l);
}
/*
@@ -3043,7 +3511,7 @@ static void dmi_fixup_type_34(struct dmi_header *h, int display)
{
u8 *p = h->data;
- /* Make sure the hidden data is ASCII only */
+ /* Make sure the hidden data is ASCII only */
if (h->length == 0x10
&& is_printable(p + 0x0B, 0x10 - 0x0B))
{
@@ -3114,17 +3582,20 @@ static const char *dmi_memory_channel_type(u8 code)
return out_of_spec;
}
-static void dmi_memory_channel_devices(u8 count, const u8 *p, const char *prefix)
+static void dmi_memory_channel_devices(u8 count, const u8 *p)
{
+ char attr[18];
int i;
for (i = 1; i <= count; i++)
{
- printf("%sDevice %u Load: %u\n",
- prefix, i, p[3 * i]);
+ sprintf(attr, "Device %hhu Load", (u8)i);
+ pr_attr(attr, "%u", p[3 * i]);
if (!(opt.flags & FLAG_QUIET))
- printf("%sDevice %u Handle: 0x%04X\n",
- prefix, i, WORD(p + 3 * i + 1));
+ {
+ sprintf(attr, "Device %hhu Handle", (u8)i);
+ pr_attr(attr, "0x%04X", WORD(p + 3 * i + 1));
+ }
}
}
@@ -3152,12 +3623,13 @@ static void dmi_ipmi_base_address(u8 type, const u8 *p, u8 lsb)
{
if (type == 0x04) /* SSIF */
{
- printf("0x%02X (SMBus)", (*p) >> 1);
+ pr_attr("Base Address", "0x%02X (SMBus)", (*p) >> 1);
}
else
{
u64 address = QWORD(p);
- printf("0x%08X%08X (%s)", address.h, (address.l & ~1) | lsb,
+ pr_attr("Base Address", "0x%08X%08X (%s)",
+ address.h, (address.l & ~1) | lsb,
address.l & 1 ? "I/O" : "Memory-mapped");
}
}
@@ -3183,9 +3655,9 @@ static const char *dmi_ipmi_register_spacing(u8 code)
static void dmi_power_supply_power(u16 code)
{
if (code == 0x8000)
- printf(" Unknown");
+ pr_attr("Max Power Capacity", "Unknown");
else
- printf(" %u W", (unsigned int)code);
+ pr_attr("Max Power Capacity", "%u W", (unsigned int)code);
}
static const char *dmi_power_supply_type(u8 code)
@@ -3248,7 +3720,7 @@ static const char *dmi_power_supply_range_switching(u8 code)
* whether it's worth the effort.
*/
-static void dmi_additional_info(const struct dmi_header *h, const char *prefix)
+static void dmi_additional_info(const struct dmi_header *h)
{
u8 *p = h->data + 4;
u8 count = *p++;
@@ -3257,37 +3729,35 @@ static void dmi_additional_info(const struct dmi_header *h, const char *prefix)
for (i = 0; i < count; i++)
{
- printf("%sAdditional Information %d\n", prefix, i + 1);
+ pr_handle_name("Additional Information %d", i + 1);
/* Check for short entries */
if (h->length < offset + 1) break;
length = p[0x00];
if (length < 0x05 || h->length < offset + length) break;
- printf("%s\tReferenced Handle: 0x%04x\n",
- prefix, WORD(p + 0x01));
- printf("%s\tReferenced Offset: 0x%02x\n",
- prefix, p[0x03]);
- printf("%s\tString: %s\n",
- prefix, dmi_string(h, p[0x04]));
+ pr_attr("Referenced Handle", "0x%04x",
+ WORD(p + 0x01));
+ pr_attr("Referenced Offset", "0x%02x",
+ p[0x03]);
+ pr_attr("String", "%s",
+ dmi_string(h, p[0x04]));
- printf("%s\tValue: ", prefix);
switch (length - 0x05)
{
case 1:
- printf("0x%02x", p[0x05]);
+ pr_attr("Value", "0x%02x", p[0x05]);
break;
case 2:
- printf("0x%04x", WORD(p + 0x05));
+ pr_attr("Value", "0x%04x", WORD(p + 0x05));
break;
case 4:
- printf("0x%08x", DWORD(p + 0x05));
+ pr_attr("Value", "0x%08x", DWORD(p + 0x05));
break;
default:
- printf("Unexpected size");
+ pr_attr("Value", "Unexpected size");
break;
}
- printf("\n");
p += length;
offset += length;
@@ -3313,12 +3783,384 @@ static const char *dmi_management_controller_host_type(u8 code)
if (code >= 0x02 && code <= 0x08)
return type[code - 0x02];
+ if (code <= 0x3F)
+ return "MCTP";
+ if (code == 0x40)
+ return "Network";
if (code == 0xF0)
return "OEM";
return out_of_spec;
}
/*
+ * 7.43.2: Protocol Record Types
+ */
+static const char *dmi_protocol_record_type(u8 type)
+{
+ const char *protocol[] = {
+ "Reserved", /* 0x0 */
+ "Reserved",
+ "IPMI",
+ "MCTP",
+ "Redfish over IP", /* 0x4 */
+ };
+
+ if (type <= 0x4)
+ return protocol[type];
+ if (type == 0xF0)
+ return "OEM";
+ return out_of_spec;
+}
+
+/*
+ * DSP0270: 8.6: Protocol IP Assignment types
+ */
+static const char *dmi_protocol_assignment_type(u8 type)
+{
+ const char *assignment[] = {
+ "Unknown", /* 0x0 */
+ "Static",
+ "DHCP",
+ "AutoConf",
+ "Host Selected", /* 0x4 */
+ };
+
+ if (type <= 0x4)
+ return assignment[type];
+ return out_of_spec;
+}
+
+/*
+ * DSP0270: 8.6: Protocol IP Address type
+ */
+static const char *dmi_address_type(u8 type)
+{
+ const char *addressformat[] = {
+ "Unknown", /* 0x0 */
+ "IPv4",
+ "IPv6", /* 0x2 */
+ };
+
+ if (type <= 0x2)
+ return addressformat[type];
+ return out_of_spec;
+}
+
+/*
+ * DSP0270: 8.6 Protocol Address decode
+ */
+static const char *dmi_address_decode(u8 *data, char *storage, u8 addrtype)
+{
+ if (addrtype == 0x1) /* IPv4 */
+ return inet_ntop(AF_INET, data, storage, 64);
+ if (addrtype == 0x2) /* IPv6 */
+ return inet_ntop(AF_INET6, data, storage, 64);
+ return out_of_spec;
+}
+
+/*
+ * DSP0270: 8.5: Parse the protocol record format
+ */
+static void dmi_parse_protocol_record(u8 *rec)
+{
+ u8 rid;
+ u8 rlen;
+ u8 *rdata;
+ char buf[64];
+ u8 assign_val;
+ u8 addrtype;
+ u8 hlen;
+ const char *addrstr;
+ const char *hname;
+ char attr[38];
+
+ /* DSP0270: 8.5: Protocol Identifier */
+ rid = rec[0x0];
+ /* DSP0270: 8.5: Protocol Record Length */
+ rlen = rec[0x1];
+ /* DSP0270: 8.5: Protocol Record Data */
+ rdata = &rec[0x2];
+
+ pr_attr("Protocol ID", "%02x (%s)", rid,
+ dmi_protocol_record_type(rid));
+
+ /*
+ * Don't decode anything other than Redfish for now
+ * Note 0x4 is Redfish over IP in 7.43.2
+ * and DSP0270: 8.5
+ */
+ if (rid != 0x4)
+ return;
+
+ /*
+ * Ensure that the protocol record is of sufficient length
+ * For RedFish that means rlen must be at least 91 bytes
+ * other protcols will need different length checks
+ */
+ if (rlen < 91)
+ return;
+
+ /*
+ * DSP0270: 8.6: Redfish Over IP Service UUID
+ * Note: ver is hardcoded to 0x311 here just for
+ * convenience. It could get passed from the SMBIOS
+ * header, but that's a lot of passing of pointers just
+ * to get that info, and the only thing it is used for is
+ * to determine the endianness of the field. Since we only
+ * do this parsing on versions of SMBIOS after 3.1.1, and the
+ * endianness of the field is always little after version 2.6.0
+ * we can just pick a sufficiently recent version here.
+ */
+ dmi_system_uuid(pr_subattr, "Service UUID", &rdata[0], 0x311);
+
+ /*
+ * DSP0270: 8.6: Redfish Over IP Host IP Assignment Type
+ * Note, using decimal indices here, as the DSP0270
+ * uses decimal, so as to make it more comparable
+ */
+ assign_val = rdata[16];
+ pr_subattr("Host IP Assignment Type", "%s",
+ dmi_protocol_assignment_type(assign_val));
+
+ /* DSP0270: 8.6: Redfish Over IP Host Address format */
+ addrtype = rdata[17];
+ addrstr = dmi_address_type(addrtype);
+ pr_subattr("Host IP Address Format", "%s",
+ addrstr);
+
+ /* DSP0270: 8.6 IP Assignment types */
+ /* We only use the Host IP Address and Mask if the assignment type is static */
+ if (assign_val == 0x1 || assign_val == 0x3)
+ {
+ /* DSP0270: 8.6: the Host IPv[4|6] Address */
+ sprintf(attr, "%s Address", addrstr);
+ pr_subattr(attr, "%s",
+ dmi_address_decode(&rdata[18], buf, addrtype));
+
+ /* DSP0270: 8.6: Prints the Host IPv[4|6] Mask */
+ sprintf(attr, "%s Mask", addrstr);
+ pr_subattr(attr, "%s",
+ dmi_address_decode(&rdata[34], buf, addrtype));
+ }
+
+ /* DSP0270: 8.6: Get the Redfish Service IP Discovery Type */
+ assign_val = rdata[50];
+ /* Redfish Service IP Discovery type mirrors Host IP Assignment type */
+ pr_subattr("Redfish Service IP Discovery Type", "%s",
+ dmi_protocol_assignment_type(assign_val));
+
+ /* DSP0270: 8.6: Get the Redfish Service IP Address Format */
+ addrtype = rdata[51];
+ addrstr = dmi_address_type(addrtype);
+ pr_subattr("Redfish Service IP Address Format", "%s",
+ addrstr);
+
+ if (assign_val == 0x1 || assign_val == 0x3)
+ {
+ u16 port;
+ u32 vlan;
+
+ /* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Address */
+ sprintf(attr, "%s Redfish Service Address", addrstr);
+ pr_subattr(attr, "%s",
+ dmi_address_decode(&rdata[52], buf,
+ addrtype));
+
+ /* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Mask */
+ sprintf(attr, "%s Redfish Service Mask", addrstr);
+ pr_subattr(attr, "%s",
+ dmi_address_decode(&rdata[68], buf,
+ addrtype));
+
+ /* DSP0270: 8.6: Redfish vlan and port info */
+ port = WORD(&rdata[84]);
+ vlan = DWORD(&rdata[86]);
+ pr_subattr("Redfish Service Port", "%hu", port);
+ pr_subattr("Redfish Service Vlan", "%u", vlan);
+ }
+
+ /* DSP0270: 8.6: Redfish host length and name */
+ hlen = rdata[90];
+
+ /*
+ * DSP0270: 8.6: The length of the host string + 91 (the minimum
+ * size of a protocol record) cannot exceed the record length
+ * (rec[0x1])
+ */
+ hname = (const char *)&rdata[91];
+ if (hlen + 91 > rlen)
+ {
+ hname = out_of_spec;
+ hlen = strlen(out_of_spec);
+ }
+ pr_subattr("Redfish Service Hostname", "%.*s", hlen, hname);
+}
+
+/*
+ * DSP0270: 8.3: Device type ennumeration
+ */
+static const char *dmi_parse_device_type(u8 type)
+{
+ const char *devname[] = {
+ "USB", /* 0x2 */
+ "PCI/PCIe", /* 0x3 */
+ };
+
+ if (type >= 0x2 && type <= 0x3)
+ return devname[type - 0x2];
+ if (type >= 0x80)
+ return "OEM";
+ return out_of_spec;
+}
+
+static void dmi_parse_controller_structure(const struct dmi_header *h)
+{
+ int i;
+ u8 *data = h->data;
+ /* Host interface type */
+ u8 type;
+ /* Host Interface specific data length */
+ u8 len;
+ u8 count;
+ u32 total_read;
+
+ /*
+ * Minimum length of this struct is 0xB bytes
+ */
+ if (h->length < 0xB)
+ return;
+
+ /*
+ * Also need to ensure that the interface specific data length
+ * plus the size of the structure to that point don't exceed
+ * the defined length of the structure, or we will overrun its
+ * bounds
+ */
+ len = data[0x5];
+ total_read = len + 0x6;
+
+ if (total_read > h->length)
+ return;
+
+ type = data[0x4];
+ pr_attr("Host Interface Type", "%s",
+ dmi_management_controller_host_type(type));
+
+ /*
+ * The following decodes are code for Network interface host types only
+ * As defined in DSP0270
+ */
+ if (type != 0x40)
+ return;
+
+ if (len != 0)
+ {
+ /* DSP0270: 8.3 Table 2: Device Type */
+ type = data[0x6];
+
+ pr_attr("Device Type", "%s",
+ dmi_parse_device_type(type));
+ if (type == 0x2 && len >= 5)
+ {
+ /* USB Device Type - need at least 6 bytes */
+ u8 *usbdata = &data[0x7];
+ /* USB Device Descriptor: idVendor */
+ pr_attr("idVendor", "0x%04x",
+ WORD(&usbdata[0x0]));
+ /* USB Device Descriptor: idProduct */
+ pr_attr("idProduct", "0x%04x",
+ WORD(&usbdata[0x2]));
+ /*
+ * USB Serial number is here, but its useless, don't
+ * bother decoding it
+ */
+ }
+ else if (type == 0x3 && len >= 9)
+ {
+ /* PCI Device Type - Need at least 8 bytes */
+ u8 *pcidata = &data[0x7];
+ /* PCI Device Descriptor: VendorID */
+ pr_attr("VendorID", "0x%04x",
+ WORD(&pcidata[0x0]));
+ /* PCI Device Descriptor: DeviceID */
+ pr_attr("DeviceID", "0x%04x",
+ WORD(&pcidata[0x2]));
+ /* PCI Device Descriptor: PCI SubvendorID */
+ pr_attr("SubVendorID", "0x%04x",
+ WORD(&pcidata[0x4]));
+ /* PCI Device Descriptor: PCI SubdeviceID */
+ pr_attr("SubDeviceID", "0x%04x",
+ WORD(&pcidata[0x6]));
+ }
+ else if (type == 0x4 && len >= 5)
+ {
+ /* OEM Device Type - Need at least 4 bytes */
+ u8 *oemdata = &data[0x7];
+ /* OEM Device Descriptor: IANA */
+ pr_attr("Vendor ID", "0x%02x:0x%02x:0x%02x:0x%02x",
+ oemdata[0x0], oemdata[0x1],
+ oemdata[0x2], oemdata[0x3]);
+ }
+ /* Don't mess with unknown types for now */
+ }
+
+ /*
+ * DSP0270: 8.2 and 8.5: Protocol record count and protocol records
+ * Move to the Protocol Count.
+ */
+ data = &data[total_read];
+
+ /*
+ * We've validated up to 0x6 + len bytes, but we need to validate
+ * the next byte below, the count value.
+ */
+ total_read++;
+ if (total_read > h->length)
+ {
+ fprintf(stderr,
+ "Total read length %d exceeds total structure length %d (handle 0x%04hx)\n",
+ total_read, h->length, h->handle);
+ return;
+ }
+
+ /* Get the protocol records count */
+ count = data[0x0];
+ if (count)
+ {
+ u8 *rec = &data[0x1];
+ for (i = 0; i < count; i++)
+ {
+ /*
+ * Need to ensure that this record doesn't overrun
+ * the total length of the type 42 struct. Note the +2
+ * is added for the two leading bytes of a protocol
+ * record representing the type and length bytes.
+ */
+ total_read += rec[1] + 2;
+ if (total_read > h->length)
+ {
+ fprintf(stderr,
+ "Total read length %d exceeds total structure length %d (handle 0x%04hx, record %d)\n",
+ total_read, h->length, h->handle, i + 1);
+ return;
+ }
+
+ dmi_parse_protocol_record(rec);
+
+ /*
+ * DSP0270: 8.6
+ * Each record is rec[1] bytes long, starting at the
+ * data byte immediately following the length field.
+ * That means we need to add the byte for the rec id,
+ * the byte for the length field, and the value of the
+ * length field itself.
+ */
+ rec += rec[1] + 2;
+ }
+ }
+}
+
+/*
* 7.44 TPM Device (Type 43)
*/
@@ -3339,10 +4181,10 @@ static void dmi_tpm_vendor_id(const u8 *p)
/* Terminate the string */
vendor_id[i] = '\0';
- printf(" %s", vendor_id);
+ pr_attr("Vendor ID", "%s", vendor_id);
}
-static void dmi_tpm_characteristics(u64 code, const char *prefix)
+static void dmi_tpm_characteristics(u64 code)
{
/* 7.1.1 */
static const char *characteristics[] = {
@@ -3358,15 +4200,60 @@ static void dmi_tpm_characteristics(u64 code, const char *prefix)
*/
if (code.l & (1 << 2))
{
- printf("%s%s\n",
- prefix, characteristics[0]);
+ pr_list_item("%s", characteristics[0]);
return;
}
for (i = 3; i <= 5; i++)
if (code.l & (1 << i))
- printf("%s%s\n",
- prefix, characteristics[i - 2]);
+ pr_list_item("%s", characteristics[i - 2]);
+}
+
+/*
+ * 7.46 Firmware Inventory Information (Type 45)
+ */
+
+static void dmi_firmware_characteristics(u16 code)
+{
+ /* 7.46.3 */
+ static const char *characteristics[] = {
+ "Updatable", /* 0 */
+ "Write-Protect" /* 1 */
+ };
+ int i;
+
+ for (i = 0; i <= 1; i++)
+ pr_list_item("%s: %s", characteristics[i],
+ (code & (1 << i)) ? "Yes" : "No");
+}
+
+static const char *dmi_firmware_state(u8 code)
+{
+ /* 7.46.4 */
+ static const char *state[] = {
+ "Other", /* 0x01 */
+ "Unknown",
+ "Disabled",
+ "Enabled",
+ "Absent",
+ "Stand-by Offline",
+ "Stand-by Spare",
+ "Unavailable Offline" /* 0x08 */
+ };
+
+ if (code >= 0x01 && code <= 0x08)
+ return state[code - 0x01];
+ return out_of_spec;
+}
+
+static void dmi_firmware_components(u8 count, const u8 *p)
+{
+ int i;
+
+ pr_list_start("Associated Components", "%u", count);
+ for (i = 0; i < count; i++)
+ pr_list_item("0x%04X", WORD(p + sizeof(u16) * i));
+ pr_list_end();
}
/*
@@ -3383,434 +4270,396 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
switch (h->type)
{
case 0: /* 7.1 BIOS Information */
- printf("BIOS Information\n");
+ pr_handle_name("BIOS Information");
if (h->length < 0x12) break;
- printf("\tVendor: %s\n",
+ pr_attr("Vendor", "%s",
dmi_string(h, data[0x04]));
- printf("\tVersion: %s\n",
+ pr_attr("Version", "%s",
dmi_string(h, data[0x05]));
- printf("\tRelease Date: %s\n",
+ pr_attr("Release Date", "%s",
dmi_string(h, data[0x08]));
/*
- * On IA-64, the BIOS base address will read 0 because
- * there is no BIOS. Skip the base address and the
- * runtime size in this case.
+ * On IA-64 and UEFI-based systems, the BIOS base
+ * address will read 0 because there is no BIOS. Skip
+ * the base address and the runtime size in this case.
*/
if (WORD(data + 0x06) != 0)
{
- printf("\tAddress: 0x%04X0\n",
+ pr_attr("Address", "0x%04X0",
WORD(data + 0x06));
- printf("\tRuntime Size:");
dmi_bios_runtime_size((0x10000 - WORD(data + 0x06)) << 4);
- printf("\n");
}
- printf("\tROM Size:");
dmi_bios_rom_size(data[0x09], h->length < 0x1A ? 16 : WORD(data + 0x18));
- printf("\n");
- printf("\tCharacteristics:\n");
- dmi_bios_characteristics(QWORD(data + 0x0A), "\t\t");
+ pr_list_start("Characteristics", NULL);
+ dmi_bios_characteristics(QWORD(data + 0x0A));
+ pr_list_end();
if (h->length < 0x13) break;
- dmi_bios_characteristics_x1(data[0x12], "\t\t");
+ dmi_bios_characteristics_x1(data[0x12]);
if (h->length < 0x14) break;
- dmi_bios_characteristics_x2(data[0x13], "\t\t");
+ dmi_bios_characteristics_x2(data[0x13]);
if (h->length < 0x18) break;
if (data[0x14] != 0xFF && data[0x15] != 0xFF)
- printf("\tBIOS Revision: %u.%u\n",
+ pr_attr("BIOS Revision", "%u.%u",
data[0x14], data[0x15]);
if (data[0x16] != 0xFF && data[0x17] != 0xFF)
- printf("\tFirmware Revision: %u.%u\n",
+ pr_attr("Firmware Revision", "%u.%u",
data[0x16], data[0x17]);
break;
case 1: /* 7.2 System Information */
- printf("System Information\n");
+ pr_handle_name("System Information");
if (h->length < 0x08) break;
- printf("\tManufacturer: %s\n",
+ pr_attr("Manufacturer", "%s",
dmi_string(h, data[0x04]));
- printf("\tProduct Name: %s\n",
+ pr_attr("Product Name", "%s",
dmi_string(h, data[0x05]));
- printf("\tVersion: %s\n",
+ pr_attr("Version", "%s",
dmi_string(h, data[0x06]));
- printf("\tSerial Number: %s\n",
+ pr_attr("Serial Number", "%s",
dmi_string(h, data[0x07]));
if (h->length < 0x19) break;
- printf("\tUUID: ");
- dmi_system_uuid(data + 0x08, ver);
- printf("\n");
- printf("\tWake-up Type: %s\n",
+ dmi_system_uuid(pr_attr, "UUID", data + 0x08, ver);
+ pr_attr("Wake-up Type", "%s",
dmi_system_wake_up_type(data[0x18]));
if (h->length < 0x1B) break;
- printf("\tSKU Number: %s\n",
+ pr_attr("SKU Number", "%s",
dmi_string(h, data[0x19]));
- printf("\tFamily: %s\n",
+ pr_attr("Family", "%s",
dmi_string(h, data[0x1A]));
break;
case 2: /* 7.3 Base Board Information */
- printf("Base Board Information\n");
+ pr_handle_name("Base Board Information");
if (h->length < 0x08) break;
- printf("\tManufacturer: %s\n",
+ pr_attr("Manufacturer", "%s",
dmi_string(h, data[0x04]));
- printf("\tProduct Name: %s\n",
+ pr_attr("Product Name", "%s",
dmi_string(h, data[0x05]));
- printf("\tVersion: %s\n",
+ pr_attr("Version", "%s",
dmi_string(h, data[0x06]));
- printf("\tSerial Number: %s\n",
+ pr_attr("Serial Number", "%s",
dmi_string(h, data[0x07]));
if (h->length < 0x09) break;
- printf("\tAsset Tag: %s\n",
+ pr_attr("Asset Tag", "%s",
dmi_string(h, data[0x08]));
if (h->length < 0x0A) break;
- printf("\tFeatures:");
- dmi_base_board_features(data[0x09], "\t\t");
+ dmi_base_board_features(data[0x09]);
if (h->length < 0x0E) break;
- printf("\tLocation In Chassis: %s\n",
+ pr_attr("Location In Chassis", "%s",
dmi_string(h, data[0x0A]));
if (!(opt.flags & FLAG_QUIET))
- printf("\tChassis Handle: 0x%04X\n",
+ pr_attr("Chassis Handle", "0x%04X",
WORD(data + 0x0B));
- printf("\tType: %s\n",
+ pr_attr("Type", "%s",
dmi_base_board_type(data[0x0D]));
if (h->length < 0x0F) break;
if (h->length < 0x0F + data[0x0E] * sizeof(u16)) break;
if (!(opt.flags & FLAG_QUIET))
- dmi_base_board_handles(data[0x0E], data + 0x0F, "\t");
+ dmi_base_board_handles(data[0x0E], data + 0x0F);
break;
case 3: /* 7.4 Chassis Information */
- printf("Chassis Information\n");
+ pr_handle_name("Chassis Information");
if (h->length < 0x09) break;
- printf("\tManufacturer: %s\n",
+ pr_attr("Manufacturer", "%s",
dmi_string(h, data[0x04]));
- printf("\tType: %s\n",
+ pr_attr("Type", "%s",
dmi_chassis_type(data[0x05]));
- printf("\tLock: %s\n",
+ pr_attr("Lock", "%s",
dmi_chassis_lock(data[0x05] >> 7));
- printf("\tVersion: %s\n",
+ pr_attr("Version", "%s",
dmi_string(h, data[0x06]));
- printf("\tSerial Number: %s\n",
+ pr_attr("Serial Number", "%s",
dmi_string(h, data[0x07]));
- printf("\tAsset Tag: %s\n",
+ pr_attr("Asset Tag", "%s",
dmi_string(h, data[0x08]));
if (h->length < 0x0D) break;
- printf("\tBoot-up State: %s\n",
+ pr_attr("Boot-up State", "%s",
dmi_chassis_state(data[0x09]));
- printf("\tPower Supply State: %s\n",
+ pr_attr("Power Supply State", "%s",
dmi_chassis_state(data[0x0A]));
- printf("\tThermal State: %s\n",
+ pr_attr("Thermal State", "%s",
dmi_chassis_state(data[0x0B]));
- printf("\tSecurity Status: %s\n",
+ pr_attr("Security Status", "%s",
dmi_chassis_security_status(data[0x0C]));
if (h->length < 0x11) break;
- printf("\tOEM Information: 0x%08X\n",
+ pr_attr("OEM Information", "0x%08X",
DWORD(data + 0x0D));
if (h->length < 0x13) break;
- printf("\tHeight:");
dmi_chassis_height(data[0x11]);
- printf("\n");
- printf("\tNumber Of Power Cords:");
dmi_chassis_power_cords(data[0x12]);
- printf("\n");
if (h->length < 0x15) break;
if (h->length < 0x15 + data[0x13] * data[0x14]) break;
- dmi_chassis_elements(data[0x13], data[0x14], data + 0x15, "\t");
+ dmi_chassis_elements(data[0x13], data[0x14], data + 0x15);
if (h->length < 0x16 + data[0x13] * data[0x14]) break;
- printf("\tSKU Number: %s\n",
+ pr_attr("SKU Number", "%s",
dmi_string(h, data[0x15 + data[0x13] * data[0x14]]));
break;
case 4: /* 7.5 Processor Information */
- printf("Processor Information\n");
+ pr_handle_name("Processor Information");
if (h->length < 0x1A) break;
- printf("\tSocket Designation: %s\n",
+ pr_attr("Socket Designation", "%s",
dmi_string(h, data[0x04]));
- printf("\tType: %s\n",
+ pr_attr("Type", "%s",
dmi_processor_type(data[0x05]));
- printf("\tFamily: %s\n",
+ pr_attr("Family", "%s",
dmi_processor_family(h, ver));
- printf("\tManufacturer: %s\n",
+ pr_attr("Manufacturer", "%s",
dmi_string(h, data[0x07]));
- dmi_processor_id(h, "\t");
- printf("\tVersion: %s\n",
+ dmi_processor_id(h);
+ pr_attr("Version", "%s",
dmi_string(h, data[0x10]));
- printf("\tVoltage:");
- dmi_processor_voltage(data[0x11]);
- printf("\n");
- printf("\tExternal Clock: ");
- dmi_processor_frequency(data + 0x12);
- printf("\n");
- printf("\tMax Speed: ");
- dmi_processor_frequency(data + 0x14);
- printf("\n");
- printf("\tCurrent Speed: ");
- dmi_processor_frequency(data + 0x16);
- printf("\n");
+ dmi_processor_voltage("Voltage", data[0x11]);
+ dmi_processor_frequency("External Clock", data + 0x12);
+ dmi_processor_frequency("Max Speed", data + 0x14);
+ dmi_processor_frequency("Current Speed", data + 0x16);
if (data[0x18] & (1 << 6))
- printf("\tStatus: Populated, %s\n",
+ pr_attr("Status", "Populated, %s",
dmi_processor_status(data[0x18] & 0x07));
else
- printf("\tStatus: Unpopulated\n");
- printf("\tUpgrade: %s\n",
+ pr_attr("Status", "Unpopulated");
+ pr_attr("Upgrade", "%s",
dmi_processor_upgrade(data[0x19]));
if (h->length < 0x20) break;
if (!(opt.flags & FLAG_QUIET))
{
- printf("\tL1 Cache Handle:");
- dmi_processor_cache(WORD(data + 0x1A), "L1", ver);
- printf("\n");
- printf("\tL2 Cache Handle:");
- dmi_processor_cache(WORD(data + 0x1C), "L2", ver);
- printf("\n");
- printf("\tL3 Cache Handle:");
- dmi_processor_cache(WORD(data + 0x1E), "L3", ver);
- printf("\n");
+ dmi_processor_cache("L1 Cache Handle",
+ WORD(data + 0x1A), "L1", ver);
+ dmi_processor_cache("L2 Cache Handle",
+ WORD(data + 0x1C), "L2", ver);
+ dmi_processor_cache("L3 Cache Handle",
+ WORD(data + 0x1E), "L3", ver);
}
if (h->length < 0x23) break;
- printf("\tSerial Number: %s\n",
+ pr_attr("Serial Number", "%s",
dmi_string(h, data[0x20]));
- printf("\tAsset Tag: %s\n",
+ pr_attr("Asset Tag", "%s",
dmi_string(h, data[0x21]));
- printf("\tPart Number: %s\n",
+ pr_attr("Part Number", "%s",
dmi_string(h, data[0x22]));
if (h->length < 0x28) break;
if (data[0x23] != 0)
- printf("\tCore Count: %u\n",
+ pr_attr("Core Count", "%u",
h->length >= 0x2C && data[0x23] == 0xFF ?
WORD(data + 0x2A) : data[0x23]);
if (data[0x24] != 0)
- printf("\tCore Enabled: %u\n",
+ pr_attr("Core Enabled", "%u",
h->length >= 0x2E && data[0x24] == 0xFF ?
WORD(data + 0x2C) : data[0x24]);
if (data[0x25] != 0)
- printf("\tThread Count: %u\n",
+ pr_attr("Thread Count", "%u",
h->length >= 0x30 && data[0x25] == 0xFF ?
WORD(data + 0x2E) : data[0x25]);
- printf("\tCharacteristics:");
- dmi_processor_characteristics(WORD(data + 0x26), "\t\t");
+ dmi_processor_characteristics("Characteristics",
+ WORD(data + 0x26));
break;
case 5: /* 7.6 Memory Controller Information */
- printf("Memory Controller Information\n");
+ pr_handle_name("Memory Controller Information");
if (h->length < 0x0F) break;
- printf("\tError Detecting Method: %s\n",
+ pr_attr("Error Detecting Method", "%s",
dmi_memory_controller_ed_method(data[0x04]));
- printf("\tError Correcting Capabilities:");
- dmi_memory_controller_ec_capabilities(data[0x05], "\t\t");
- printf("\tSupported Interleave: %s\n",
+ dmi_memory_controller_ec_capabilities("Error Correcting Capabilities",
+ data[0x05]);
+ pr_attr("Supported Interleave", "%s",
dmi_memory_controller_interleave(data[0x06]));
- printf("\tCurrent Interleave: %s\n",
+ pr_attr("Current Interleave", "%s",
dmi_memory_controller_interleave(data[0x07]));
- printf("\tMaximum Memory Module Size: %u MB\n",
+ pr_attr("Maximum Memory Module Size", "%u MB",
1 << data[0x08]);
- printf("\tMaximum Total Memory Size: %u MB\n",
+ pr_attr("Maximum Total Memory Size", "%u MB",
data[0x0E] * (1 << data[0x08]));
- printf("\tSupported Speeds:");
- dmi_memory_controller_speeds(WORD(data + 0x09), "\t\t");
- printf("\tSupported Memory Types:");
- dmi_memory_module_types(WORD(data + 0x0B), "\n\t\t");
- printf("\n");
- printf("\tMemory Module Voltage:");
- dmi_processor_voltage(data[0x0D]);
- printf("\n");
+ dmi_memory_controller_speeds("Supported Speeds",
+ WORD(data + 0x09));
+ dmi_memory_module_types("Supported Memory Types",
+ WORD(data + 0x0B), 0);
+ dmi_processor_voltage("Memory Module Voltage", data[0x0D]);
if (h->length < 0x0F + data[0x0E] * sizeof(u16)) break;
- dmi_memory_controller_slots(data[0x0E], data + 0x0F, "\t");
+ dmi_memory_controller_slots(data[0x0E], data + 0x0F);
if (h->length < 0x10 + data[0x0E] * sizeof(u16)) break;
- printf("\tEnabled Error Correcting Capabilities:");
- dmi_memory_controller_ec_capabilities(data[0x0F + data[0x0E] * sizeof(u16)], "\t\t");
+ dmi_memory_controller_ec_capabilities("Enabled Error Correcting Capabilities",
+ data[0x0F + data[0x0E] * sizeof(u16)]);
break;
case 6: /* 7.7 Memory Module Information */
- printf("Memory Module Information\n");
+ pr_handle_name("Memory Module Information");
if (h->length < 0x0C) break;
- printf("\tSocket Designation: %s\n",
+ pr_attr("Socket Designation", "%s",
dmi_string(h, data[0x04]));
- printf("\tBank Connections:");
dmi_memory_module_connections(data[0x05]);
- printf("\n");
- printf("\tCurrent Speed:");
- dmi_memory_module_speed(data[0x06]);
- printf("\n");
- printf("\tType:");
- dmi_memory_module_types(WORD(data + 0x07), " ");
- printf("\n");
- printf("\tInstalled Size:");
- dmi_memory_module_size(data[0x09]);
- printf("\n");
- printf("\tEnabled Size:");
- dmi_memory_module_size(data[0x0A]);
- printf("\n");
- printf("\tError Status:");
- dmi_memory_module_error(data[0x0B], "\t\t");
+ dmi_memory_module_speed("Current Speed", data[0x06]);
+ dmi_memory_module_types("Type", WORD(data + 0x07), 1);
+ dmi_memory_module_size("Installed Size", data[0x09]);
+ dmi_memory_module_size("Enabled Size", data[0x0A]);
+ dmi_memory_module_error(data[0x0B]);
break;
case 7: /* 7.8 Cache Information */
- printf("Cache Information\n");
+ pr_handle_name("Cache Information");
if (h->length < 0x0F) break;
- printf("\tSocket Designation: %s\n",
+ pr_attr("Socket Designation", "%s",
dmi_string(h, data[0x04]));
- printf("\tConfiguration: %s, %s, Level %u\n",
+ pr_attr("Configuration", "%s, %s, Level %u",
WORD(data + 0x05) & 0x0080 ? "Enabled" : "Disabled",
WORD(data + 0x05) & 0x0008 ? "Socketed" : "Not Socketed",
(WORD(data + 0x05) & 0x0007) + 1);
- printf("\tOperational Mode: %s\n",
+ pr_attr("Operational Mode", "%s",
dmi_cache_mode((WORD(data + 0x05) >> 8) & 0x0003));
- printf("\tLocation: %s\n",
+ pr_attr("Location", "%s",
dmi_cache_location((WORD(data + 0x05) >> 5) & 0x0003));
- printf("\tInstalled Size:");
if (h->length >= 0x1B)
- dmi_cache_size_2(DWORD(data + 0x17));
+ dmi_cache_size_2("Installed Size", DWORD(data + 0x17));
else
- dmi_cache_size(WORD(data + 0x09));
- printf("\n");
- printf("\tMaximum Size:");
+ dmi_cache_size("Installed Size", WORD(data + 0x09));
if (h->length >= 0x17)
- dmi_cache_size_2(DWORD(data + 0x13));
+ dmi_cache_size_2("Maximum Size", DWORD(data + 0x13));
else
- dmi_cache_size(WORD(data + 0x07));
- printf("\n");
- printf("\tSupported SRAM Types:");
- dmi_cache_types(WORD(data + 0x0B), "\n\t\t");
- printf("\n");
- printf("\tInstalled SRAM Type:");
- dmi_cache_types(WORD(data + 0x0D), " ");
- printf("\n");
+ dmi_cache_size("Maximum Size", WORD(data + 0x07));
+ dmi_cache_types("Supported SRAM Types", WORD(data + 0x0B), 0);
+ dmi_cache_types("Installed SRAM Type", WORD(data + 0x0D), 1);
if (h->length < 0x13) break;
- printf("\tSpeed:");
- dmi_memory_module_speed(data[0x0F]);
- printf("\n");
- printf("\tError Correction Type: %s\n",
+ dmi_memory_module_speed("Speed", data[0x0F]);
+ pr_attr("Error Correction Type", "%s",
dmi_cache_ec_type(data[0x10]));
- printf("\tSystem Type: %s\n",
+ pr_attr("System Type", "%s",
dmi_cache_type(data[0x11]));
- printf("\tAssociativity: %s\n",
+ pr_attr("Associativity", "%s",
dmi_cache_associativity(data[0x12]));
break;
case 8: /* 7.9 Port Connector Information */
- printf("Port Connector Information\n");
+ pr_handle_name("Port Connector Information");
if (h->length < 0x09) break;
- printf("\tInternal Reference Designator: %s\n",
+ pr_attr("Internal Reference Designator", "%s",
dmi_string(h, data[0x04]));
- printf("\tInternal Connector Type: %s\n",
+ pr_attr("Internal Connector Type", "%s",
dmi_port_connector_type(data[0x05]));
- printf("\tExternal Reference Designator: %s\n",
+ pr_attr("External Reference Designator", "%s",
dmi_string(h, data[0x06]));
- printf("\tExternal Connector Type: %s\n",
+ pr_attr("External Connector Type", "%s",
dmi_port_connector_type(data[0x07]));
- printf("\tPort Type: %s\n",
+ pr_attr("Port Type", "%s",
dmi_port_type(data[0x08]));
break;
case 9: /* 7.10 System Slots */
- printf("System Slot Information\n");
+ pr_handle_name("System Slot Information");
if (h->length < 0x0C) break;
- printf("\tDesignation: %s\n",
+ pr_attr("Designation", "%s",
dmi_string(h, data[0x04]));
- printf("\tType: %s%s\n",
- dmi_slot_bus_width(data[0x06]),
- dmi_slot_type(data[0x05]));
- printf("\tCurrent Usage: %s\n",
+ dmi_slot_type_with_width(data[0x05], data[0x06]);
+ pr_attr("Current Usage", "%s",
dmi_slot_current_usage(data[0x07]));
- printf("\tLength: %s\n",
+ pr_attr("Length", "%s",
dmi_slot_length(data[0x08]));
- dmi_slot_id(data[0x09], data[0x0A], data[0x05], "\t");
- printf("\tCharacteristics:");
+ dmi_slot_id(data[0x09], data[0x0A], data[0x05]);
if (h->length < 0x0D)
- dmi_slot_characteristics(data[0x0B], 0x00, "\t\t");
+ dmi_slot_characteristics("Characteristics", data[0x0B], 0x00);
else
- dmi_slot_characteristics(data[0x0B], data[0x0C], "\t\t");
+ dmi_slot_characteristics("Characteristics", data[0x0B], data[0x0C]);
if (h->length < 0x11) break;
- dmi_slot_segment_bus_func(WORD(data + 0x0D), data[0x0F], data[0x10], "\t");
+ dmi_slot_segment_bus_func(WORD(data + 0x0D), data[0x0F], data[0x10]);
+ if (h->length < 0x13) break;
+ pr_attr("Data Bus Width", "%u", data[0x11]);
+ pr_attr("Peer Devices", "%u", data[0x12]);
+ if (h->length < 0x13 + data[0x12] * 5) break;
+ dmi_slot_peers(data[0x12], data + 0x13);
+ if (h->length < 0x17 + data[0x12] * 5) break;
+ dmi_slot_information(data[0x05], data[0x13 + data[0x12] * 5]);
+ dmi_slot_physical_width(data[0x14 + data[0x12] * 5]);
+ dmi_slot_pitch(WORD(data + 0x15 + data[0x12] * 5));
+ if (h->length < 0x18 + data[0x12] * 5) break;
+ pr_attr("Height", "%s",
+ dmi_slot_height(data[0x17 + data[0x12] * 5]));
break;
case 10: /* 7.11 On Board Devices Information */
- dmi_on_board_devices(h, "");
+ dmi_on_board_devices(h);
break;
case 11: /* 7.12 OEM Strings */
- printf("OEM Strings\n");
+ pr_handle_name("OEM Strings");
if (h->length < 0x05) break;
- dmi_oem_strings(h, "\t");
+ dmi_oem_strings(h);
break;
case 12: /* 7.13 System Configuration Options */
- printf("System Configuration Options\n");
+ pr_handle_name("System Configuration Options");
if (h->length < 0x05) break;
- dmi_system_configuration_options(h, "\t");
+ dmi_system_configuration_options(h);
break;
case 13: /* 7.14 BIOS Language Information */
- printf("BIOS Language Information\n");
+ pr_handle_name("BIOS Language Information");
if (h->length < 0x16) break;
if (ver >= 0x0201)
{
- printf("\tLanguage Description Format: %s\n",
+ pr_attr("Language Description Format", "%s",
dmi_bios_language_format(data[0x05]));
}
- printf("\tInstallable Languages: %u\n", data[0x04]);
- dmi_bios_languages(h, "\t\t");
- printf("\tCurrently Installed Language: %s\n",
+ pr_list_start("Installable Languages", "%u", data[0x04]);
+ dmi_bios_languages(h);
+ pr_list_end();
+ pr_attr("Currently Installed Language", "%s",
dmi_string(h, data[0x15]));
break;
case 14: /* 7.15 Group Associations */
- printf("Group Associations\n");
+ pr_handle_name("Group Associations");
if (h->length < 0x05) break;
- printf("\tName: %s\n",
+ pr_attr("Name", "%s",
dmi_string(h, data[0x04]));
- printf("\tItems: %u\n",
+ pr_list_start("Items", "%u",
(h->length - 0x05) / 3);
- dmi_group_associations_items((h->length - 0x05) / 3, data + 0x05, "\t\t");
+ dmi_group_associations_items((h->length - 0x05) / 3, data + 0x05);
+ pr_list_end();
break;
case 15: /* 7.16 System Event Log */
- printf("System Event Log\n");
+ pr_handle_name("System Event Log");
if (h->length < 0x14) break;
- printf("\tArea Length: %u bytes\n",
+ pr_attr("Area Length", "%u bytes",
WORD(data + 0x04));
- printf("\tHeader Start Offset: 0x%04X\n",
+ pr_attr("Header Start Offset", "0x%04X",
WORD(data + 0x06));
if (WORD(data + 0x08) - WORD(data + 0x06))
- printf("\tHeader Length: %u byte%s\n",
+ pr_attr("Header Length", "%u byte%s",
WORD(data + 0x08) - WORD(data + 0x06),
WORD(data + 0x08) - WORD(data + 0x06) > 1 ? "s" : "");
- printf("\tData Start Offset: 0x%04X\n",
+ pr_attr("Data Start Offset", "0x%04X",
WORD(data + 0x08));
- printf("\tAccess Method: %s\n",
+ pr_attr("Access Method", "%s",
dmi_event_log_method(data[0x0A]));
- printf("\tAccess Address:");
dmi_event_log_address(data[0x0A], data + 0x10);
- printf("\n");
- printf("\tStatus:");
dmi_event_log_status(data[0x0B]);
- printf("\n");
- printf("\tChange Token: 0x%08X\n",
+ pr_attr("Change Token", "0x%08X",
DWORD(data + 0x0C));
if (h->length < 0x17) break;
- printf("\tHeader Format: %s\n",
+ pr_attr("Header Format", "%s",
dmi_event_log_header_type(data[0x14]));
- printf("\tSupported Log Type Descriptors: %u\n",
+ pr_attr("Supported Log Type Descriptors", "%u",
data[0x15]);
if (h->length < 0x17 + data[0x15] * data[0x16]) break;
- dmi_event_log_descriptors(data[0x15], data[0x16], data + 0x17, "\t");
+ dmi_event_log_descriptors(data[0x15], data[0x16], data + 0x17);
break;
case 16: /* 7.17 Physical Memory Array */
- printf("Physical Memory Array\n");
+ pr_handle_name("Physical Memory Array");
if (h->length < 0x0F) break;
- printf("\tLocation: %s\n",
+ pr_attr("Location", "%s",
dmi_memory_array_location(data[0x04]));
- printf("\tUse: %s\n",
+ pr_attr("Use", "%s",
dmi_memory_array_use(data[0x05]));
- printf("\tError Correction Type: %s\n",
+ pr_attr("Error Correction Type", "%s",
dmi_memory_array_ec_type(data[0x06]));
- printf("\tMaximum Capacity:");
if (DWORD(data + 0x07) == 0x80000000)
{
if (h->length < 0x17)
- printf(" Unknown");
+ pr_attr("Maximum Capacity", "Unknown");
else
- dmi_print_memory_size(QWORD(data + 0x0F), 0);
+ dmi_print_memory_size("Maximum Capacity",
+ QWORD(data + 0x0F), 0);
}
else
{
@@ -3818,117 +4667,116 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
capacity.h = 0;
capacity.l = DWORD(data + 0x07);
- dmi_print_memory_size(capacity, 1);
+ dmi_print_memory_size("Maximum Capacity",
+ capacity, 1);
}
- printf("\n");
if (!(opt.flags & FLAG_QUIET))
- {
- printf("\tError Information Handle:");
dmi_memory_array_error_handle(WORD(data + 0x0B));
- printf("\n");
- }
- printf("\tNumber Of Devices: %u\n",
+ pr_attr("Number Of Devices", "%u",
WORD(data + 0x0D));
break;
case 17: /* 7.18 Memory Device */
- printf("Memory Device\n");
+ pr_handle_name("Memory Device");
if (h->length < 0x15) break;
if (!(opt.flags & FLAG_QUIET))
{
- printf("\tArray Handle: 0x%04X\n",
+ pr_attr("Array Handle", "0x%04X",
WORD(data + 0x04));
- printf("\tError Information Handle:");
dmi_memory_array_error_handle(WORD(data + 0x06));
- printf("\n");
}
- printf("\tTotal Width:");
- dmi_memory_device_width(WORD(data + 0x08));
- printf("\n");
- printf("\tData Width:");
- dmi_memory_device_width(WORD(data + 0x0A));
- printf("\n");
- printf("\tSize:");
+ dmi_memory_device_width("Total Width", WORD(data + 0x08));
+ dmi_memory_device_width("Data Width", WORD(data + 0x0A));
if (h->length >= 0x20 && WORD(data + 0x0C) == 0x7FFF)
dmi_memory_device_extended_size(DWORD(data + 0x1C));
else
dmi_memory_device_size(WORD(data + 0x0C));
- printf("\n");
- printf("\tForm Factor: %s\n",
+ pr_attr("Form Factor", "%s",
dmi_memory_device_form_factor(data[0x0E]));
- printf("\tSet:");
dmi_memory_device_set(data[0x0F]);
- printf("\n");
- printf("\tLocator: %s\n",
+ pr_attr("Locator", "%s",
dmi_string(h, data[0x10]));
- printf("\tBank Locator: %s\n",
+ pr_attr("Bank Locator", "%s",
dmi_string(h, data[0x11]));
- printf("\tType: %s\n",
+ pr_attr("Type", "%s",
dmi_memory_device_type(data[0x12]));
- printf("\tType Detail:");
dmi_memory_device_type_detail(WORD(data + 0x13));
- printf("\n");
if (h->length < 0x17) break;
- printf("\tSpeed:");
- dmi_memory_device_speed(WORD(data + 0x15));
- printf("\n");
+ /* If no module is present, the remaining fields are irrelevant */
+ if (WORD(data + 0x0C) == 0 && !(opt.flags & FLAG_NO_QUIRKS))
+ break;
+ dmi_memory_device_speed("Speed", WORD(data + 0x15),
+ h->length >= 0x5C ?
+ DWORD(data + 0x54) : 0);
if (h->length < 0x1B) break;
- printf("\tManufacturer: %s\n",
+ pr_attr("Manufacturer", "%s",
dmi_string(h, data[0x17]));
- printf("\tSerial Number: %s\n",
+ pr_attr("Serial Number", "%s",
dmi_string(h, data[0x18]));
- printf("\tAsset Tag: %s\n",
+ pr_attr("Asset Tag", "%s",
dmi_string(h, data[0x19]));
- printf("\tPart Number: %s\n",
+ pr_attr("Part Number", "%s",
dmi_string(h, data[0x1A]));
if (h->length < 0x1C) break;
- printf("\tRank: ");
if ((data[0x1B] & 0x0F) == 0)
- printf("Unknown");
+ pr_attr("Rank", "Unknown");
else
- printf("%u", data[0x1B] & 0x0F);
- printf("\n");
+ pr_attr("Rank", "%u", data[0x1B] & 0x0F);
if (h->length < 0x22) break;
- printf("\tConfigured Clock Speed:");
- dmi_memory_device_speed(WORD(data + 0x20));
- printf("\n");
+ dmi_memory_device_speed("Configured Memory Speed",
+ WORD(data + 0x20),
+ h->length >= 0x5C ?
+ DWORD(data + 0x58) : 0);
if (h->length < 0x28) break;
- printf("\tMinimum Voltage:");
- dmi_memory_voltage_value(WORD(data + 0x22));
- printf("\n");
- printf("\tMaximum Voltage:");
- dmi_memory_voltage_value(WORD(data + 0x24));
- printf("\n");
- printf("\tConfigured Voltage:");
- dmi_memory_voltage_value(WORD(data + 0x26));
- printf("\n");
+ dmi_memory_voltage_value("Minimum Voltage",
+ WORD(data + 0x22));
+ dmi_memory_voltage_value("Maximum Voltage",
+ WORD(data + 0x24));
+ dmi_memory_voltage_value("Configured Voltage",
+ WORD(data + 0x26));
+ if (h->length < 0x34) break;
+ dmi_memory_technology(data[0x28]);
+ dmi_memory_operating_mode_capability(WORD(data + 0x29));
+ pr_attr("Firmware Version", "%s",
+ dmi_string(h, data[0x2B]));
+ dmi_memory_manufacturer_id("Module Manufacturer ID",
+ WORD(data + 0x2C));
+ dmi_memory_product_id("Module Product ID",
+ WORD(data + 0x2E));
+ dmi_memory_manufacturer_id("Memory Subsystem Controller Manufacturer ID",
+ WORD(data + 0x30));
+ dmi_memory_product_id("Memory Subsystem Controller Product ID",
+ WORD(data + 0x32));
+ if (h->length < 0x3C) break;
+ dmi_memory_size("Non-Volatile Size", QWORD(data + 0x34));
+ if (h->length < 0x44) break;
+ dmi_memory_size("Volatile Size", QWORD(data + 0x3C));
+ if (h->length < 0x4C) break;
+ dmi_memory_size("Cache Size", QWORD(data + 0x44));
+ if (h->length < 0x54) break;
+ dmi_memory_size("Logical Size", QWORD(data + 0x4C));
break;
case 18: /* 7.19 32-bit Memory Error Information */
- printf("32-bit Memory Error Information\n");
+ pr_handle_name("32-bit Memory Error Information");
if (h->length < 0x17) break;
- printf("\tType: %s\n",
+ pr_attr("Type", "%s",
dmi_memory_error_type(data[0x04]));
- printf("\tGranularity: %s\n",
+ pr_attr("Granularity", "%s",
dmi_memory_error_granularity(data[0x05]));
- printf("\tOperation: %s\n",
+ pr_attr("Operation", "%s",
dmi_memory_error_operation(data[0x06]));
- printf("\tVendor Syndrome:");
dmi_memory_error_syndrome(DWORD(data + 0x07));
- printf("\n");
- printf("\tMemory Array Address:");
- dmi_32bit_memory_error_address(DWORD(data + 0x0B));
- printf("\n");
- printf("\tDevice Address:");
- dmi_32bit_memory_error_address(DWORD(data + 0x0F));
- printf("\n");
- printf("\tResolution:");
- dmi_32bit_memory_error_address(DWORD(data + 0x13));
- printf("\n");
+ dmi_32bit_memory_error_address("Memory Array Address",
+ DWORD(data + 0x0B));
+ dmi_32bit_memory_error_address("Device Address",
+ DWORD(data + 0x0F));
+ dmi_32bit_memory_error_address("Resolution",
+ DWORD(data + 0x13));
break;
case 19: /* 7.20 Memory Array Mapped Address */
- printf("Memory Array Mapped Address\n");
+ pr_handle_name("Memory Array Mapped Address");
if (h->length < 0x0F) break;
if (h->length >= 0x1F && DWORD(data + 0x04) == 0xFFFFFFFF)
{
@@ -3937,34 +4785,31 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
start = QWORD(data + 0x0F);
end = QWORD(data + 0x17);
- printf("\tStarting Address: 0x%08X%08Xk\n",
+ pr_attr("Starting Address", "0x%08X%08Xk",
start.h, start.l);
- printf("\tEnding Address: 0x%08X%08Xk\n",
+ pr_attr("Ending Address", "0x%08X%08Xk",
end.h, end.l);
- printf("\tRange Size:");
dmi_mapped_address_extended_size(start, end);
}
else
{
- printf("\tStarting Address: 0x%08X%03X\n",
+ pr_attr("Starting Address", "0x%08X%03X",
DWORD(data + 0x04) >> 2,
(DWORD(data + 0x04) & 0x3) << 10);
- printf("\tEnding Address: 0x%08X%03X\n",
+ pr_attr("Ending Address", "0x%08X%03X",
DWORD(data + 0x08) >> 2,
((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF);
- printf("\tRange Size:");
dmi_mapped_address_size(DWORD(data + 0x08) - DWORD(data + 0x04) + 1);
}
- printf("\n");
if (!(opt.flags & FLAG_QUIET))
- printf("\tPhysical Array Handle: 0x%04X\n",
+ pr_attr("Physical Array Handle", "0x%04X",
WORD(data + 0x0C));
- printf("\tPartition Width: %u\n",
+ pr_attr("Partition Width", "%u",
data[0x0E]);
break;
case 20: /* 7.21 Memory Device Mapped Address */
- printf("Memory Device Mapped Address\n");
+ pr_handle_name("Memory Device Mapped Address");
if (h->length < 0x13) break;
if (h->length >= 0x23 && DWORD(data + 0x04) == 0xFFFFFFFF)
{
@@ -3973,382 +4818,326 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
start = QWORD(data + 0x13);
end = QWORD(data + 0x1B);
- printf("\tStarting Address: 0x%08X%08Xk\n",
+ pr_attr("Starting Address", "0x%08X%08Xk",
start.h, start.l);
- printf("\tEnding Address: 0x%08X%08Xk\n",
+ pr_attr("Ending Address", "0x%08X%08Xk",
end.h, end.l);
- printf("\tRange Size:");
dmi_mapped_address_extended_size(start, end);
}
else
{
- printf("\tStarting Address: 0x%08X%03X\n",
+ pr_attr("Starting Address", "0x%08X%03X",
DWORD(data + 0x04) >> 2,
(DWORD(data + 0x04) & 0x3) << 10);
- printf("\tEnding Address: 0x%08X%03X\n",
+ pr_attr("Ending Address", "0x%08X%03X",
DWORD(data + 0x08) >> 2,
((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF);
- printf("\tRange Size:");
dmi_mapped_address_size(DWORD(data + 0x08) - DWORD(data + 0x04) + 1);
}
- printf("\n");
if (!(opt.flags & FLAG_QUIET))
{
- printf("\tPhysical Device Handle: 0x%04X\n",
+ pr_attr("Physical Device Handle", "0x%04X",
WORD(data + 0x0C));
- printf("\tMemory Array Mapped Address Handle: 0x%04X\n",
+ pr_attr("Memory Array Mapped Address Handle", "0x%04X",
WORD(data + 0x0E));
}
- printf("\tPartition Row Position:");
dmi_mapped_address_row_position(data[0x10]);
- printf("\n");
- dmi_mapped_address_interleave_position(data[0x11], "\t");
- dmi_mapped_address_interleaved_data_depth(data[0x12], "\t");
+ dmi_mapped_address_interleave_position(data[0x11]);
+ dmi_mapped_address_interleaved_data_depth(data[0x12]);
break;
case 21: /* 7.22 Built-in Pointing Device */
- printf("Built-in Pointing Device\n");
+ pr_handle_name("Built-in Pointing Device");
if (h->length < 0x07) break;
- printf("\tType: %s\n",
+ pr_attr("Type", "%s",
dmi_pointing_device_type(data[0x04]));
- printf("\tInterface: %s\n",
+ pr_attr("Interface", "%s",
dmi_pointing_device_interface(data[0x05]));
- printf("\tButtons: %u\n",
+ pr_attr("Buttons", "%u",
data[0x06]);
break;
case 22: /* 7.23 Portable Battery */
- printf("Portable Battery\n");
+ pr_handle_name("Portable Battery");
if (h->length < 0x10) break;
- printf("\tLocation: %s\n",
+ pr_attr("Location", "%s",
dmi_string(h, data[0x04]));
- printf("\tManufacturer: %s\n",
+ pr_attr("Manufacturer", "%s",
dmi_string(h, data[0x05]));
if (data[0x06] || h->length < 0x1A)
- printf("\tManufacture Date: %s\n",
+ pr_attr("Manufacture Date", "%s",
dmi_string(h, data[0x06]));
if (data[0x07] || h->length < 0x1A)
- printf("\tSerial Number: %s\n",
+ pr_attr("Serial Number", "%s",
dmi_string(h, data[0x07]));
- printf("\tName: %s\n",
+ pr_attr("Name", "%s",
dmi_string(h, data[0x08]));
if (data[0x09] != 0x02 || h->length < 0x1A)
- printf("\tChemistry: %s\n",
+ pr_attr("Chemistry", "%s",
dmi_battery_chemistry(data[0x09]));
- printf("\tDesign Capacity:");
if (h->length < 0x16)
dmi_battery_capacity(WORD(data + 0x0A), 1);
else
dmi_battery_capacity(WORD(data + 0x0A), data[0x15]);
- printf("\n");
- printf("\tDesign Voltage:");
dmi_battery_voltage(WORD(data + 0x0C));
- printf("\n");
- printf("\tSBDS Version: %s\n",
+ pr_attr("SBDS Version", "%s",
dmi_string(h, data[0x0E]));
- printf("\tMaximum Error:");
dmi_battery_maximum_error(data[0x0F]);
- printf("\n");
if (h->length < 0x1A) break;
if (data[0x07] == 0)
- printf("\tSBDS Serial Number: %04X\n",
+ pr_attr("SBDS Serial Number", "%04X",
WORD(data + 0x10));
if (data[0x06] == 0)
- printf("\tSBDS Manufacture Date: %u-%02u-%02u\n",
+ pr_attr("SBDS Manufacture Date", "%u-%02u-%02u",
1980 + (WORD(data + 0x12) >> 9),
(WORD(data + 0x12) >> 5) & 0x0F,
WORD(data + 0x12) & 0x1F);
if (data[0x09] == 0x02)
- printf("\tSBDS Chemistry: %s\n",
+ pr_attr("SBDS Chemistry", "%s",
dmi_string(h, data[0x14]));
- printf("\tOEM-specific Information: 0x%08X\n",
+ pr_attr("OEM-specific Information", "0x%08X",
DWORD(data + 0x16));
break;
case 23: /* 7.24 System Reset */
- printf("System Reset\n");
+ pr_handle_name("System Reset");
if (h->length < 0x0D) break;
- printf("\tStatus: %s\n",
+ pr_attr("Status", "%s",
data[0x04] & (1 << 0) ? "Enabled" : "Disabled");
- printf("\tWatchdog Timer: %s\n",
+ pr_attr("Watchdog Timer", "%s",
data[0x04] & (1 << 5) ? "Present" : "Not Present");
if (!(data[0x04] & (1 << 5)))
break;
- printf("\tBoot Option: %s\n",
+ pr_attr("Boot Option", "%s",
dmi_system_reset_boot_option((data[0x04] >> 1) & 0x3));
- printf("\tBoot Option On Limit: %s\n",
+ pr_attr("Boot Option On Limit", "%s",
dmi_system_reset_boot_option((data[0x04] >> 3) & 0x3));
- printf("\tReset Count:");
- dmi_system_reset_count(WORD(data + 0x05));
- printf("\n");
- printf("\tReset Limit:");
- dmi_system_reset_count(WORD(data + 0x07));
- printf("\n");
- printf("\tTimer Interval:");
- dmi_system_reset_timer(WORD(data + 0x09));
- printf("\n");
- printf("\tTimeout:");
- dmi_system_reset_timer(WORD(data + 0x0B));
- printf("\n");
+ dmi_system_reset_count("Reset Count", WORD(data + 0x05));
+ dmi_system_reset_count("Reset Limit", WORD(data + 0x07));
+ dmi_system_reset_timer("Timer Interval", WORD(data + 0x09));
+ dmi_system_reset_timer("Timeout", WORD(data + 0x0B));
break;
case 24: /* 7.25 Hardware Security */
- printf("Hardware Security\n");
+ pr_handle_name("Hardware Security");
if (h->length < 0x05) break;
- printf("\tPower-On Password Status: %s\n",
+ pr_attr("Power-On Password Status", "%s",
dmi_hardware_security_status(data[0x04] >> 6));
- printf("\tKeyboard Password Status: %s\n",
+ pr_attr("Keyboard Password Status", "%s",
dmi_hardware_security_status((data[0x04] >> 4) & 0x3));
- printf("\tAdministrator Password Status: %s\n",
+ pr_attr("Administrator Password Status", "%s",
dmi_hardware_security_status((data[0x04] >> 2) & 0x3));
- printf("\tFront Panel Reset Status: %s\n",
+ pr_attr("Front Panel Reset Status", "%s",
dmi_hardware_security_status(data[0x04] & 0x3));
break;
case 25: /* 7.26 System Power Controls */
- printf("\tSystem Power Controls\n");
+ pr_handle_name("System Power Controls");
if (h->length < 0x09) break;
- printf("\tNext Scheduled Power-on:");
dmi_power_controls_power_on(data + 0x04);
- printf("\n");
break;
case 26: /* 7.27 Voltage Probe */
- printf("Voltage Probe\n");
+ pr_handle_name("Voltage Probe");
if (h->length < 0x14) break;
- printf("\tDescription: %s\n",
+ pr_attr("Description", "%s",
dmi_string(h, data[0x04]));
- printf("\tLocation: %s\n",
+ pr_attr("Location", "%s",
dmi_voltage_probe_location(data[0x05] & 0x1f));
- printf("\tStatus: %s\n",
+ pr_attr("Status", "%s",
dmi_probe_status(data[0x05] >> 5));
- printf("\tMaximum Value:");
- dmi_voltage_probe_value(WORD(data + 0x06));
- printf("\n");
- printf("\tMinimum Value:");
- dmi_voltage_probe_value(WORD(data + 0x08));
- printf("\n");
- printf("\tResolution:");
+ dmi_voltage_probe_value("Maximum Value", WORD(data + 0x06));
+ dmi_voltage_probe_value("Minimum Value", WORD(data + 0x08));
dmi_voltage_probe_resolution(WORD(data + 0x0A));
- printf("\n");
- printf("\tTolerance:");
- dmi_voltage_probe_value(WORD(data + 0x0C));
- printf("\n");
- printf("\tAccuracy:");
+ dmi_voltage_probe_value("Tolerance", WORD(data + 0x0C));
dmi_probe_accuracy(WORD(data + 0x0E));
- printf("\n");
- printf("\tOEM-specific Information: 0x%08X\n",
+ pr_attr("OEM-specific Information", "0x%08X",
DWORD(data + 0x10));
if (h->length < 0x16) break;
- printf("\tNominal Value:");
- dmi_voltage_probe_value(WORD(data + 0x14));
- printf("\n");
+ dmi_voltage_probe_value("Nominal Value", WORD(data + 0x14));
break;
case 27: /* 7.28 Cooling Device */
- printf("Cooling Device\n");
+ pr_handle_name("Cooling Device");
if (h->length < 0x0C) break;
if (!(opt.flags & FLAG_QUIET) && WORD(data + 0x04) != 0xFFFF)
- printf("\tTemperature Probe Handle: 0x%04X\n",
+ pr_attr("Temperature Probe Handle", "0x%04X",
WORD(data + 0x04));
- printf("\tType: %s\n",
+ pr_attr("Type", "%s",
dmi_cooling_device_type(data[0x06] & 0x1f));
- printf("\tStatus: %s\n",
+ pr_attr("Status", "%s",
dmi_probe_status(data[0x06] >> 5));
if (data[0x07] != 0x00)
- printf("\tCooling Unit Group: %u\n",
+ pr_attr("Cooling Unit Group", "%u",
data[0x07]);
- printf("\tOEM-specific Information: 0x%08X\n",
+ pr_attr("OEM-specific Information", "0x%08X",
DWORD(data + 0x08));
if (h->length < 0x0E) break;
- printf("\tNominal Speed:");
dmi_cooling_device_speed(WORD(data + 0x0C));
- printf("\n");
if (h->length < 0x0F) break;
- printf("\tDescription: %s\n", dmi_string(h, data[0x0E]));
+ pr_attr("Description", "%s", dmi_string(h, data[0x0E]));
break;
case 28: /* 7.29 Temperature Probe */
- printf("Temperature Probe\n");
+ pr_handle_name("Temperature Probe");
if (h->length < 0x14) break;
- printf("\tDescription: %s\n",
+ pr_attr("Description", "%s",
dmi_string(h, data[0x04]));
- printf("\tLocation: %s\n",
+ pr_attr("Location", "%s",
dmi_temperature_probe_location(data[0x05] & 0x1F));
- printf("\tStatus: %s\n",
+ pr_attr("Status", "%s",
dmi_probe_status(data[0x05] >> 5));
- printf("\tMaximum Value:");
- dmi_temperature_probe_value(WORD(data + 0x06));
- printf("\n");
- printf("\tMinimum Value:");
- dmi_temperature_probe_value(WORD(data + 0x08));
- printf("\n");
- printf("\tResolution:");
+ dmi_temperature_probe_value("Maximum Value",
+ WORD(data + 0x06));
+ dmi_temperature_probe_value("Minimum Value",
+ WORD(data + 0x08));
dmi_temperature_probe_resolution(WORD(data + 0x0A));
- printf("\n");
- printf("\tTolerance:");
- dmi_temperature_probe_value(WORD(data + 0x0C));
- printf("\n");
- printf("\tAccuracy:");
+ dmi_temperature_probe_value("Tolerance",
+ WORD(data + 0x0C));
dmi_probe_accuracy(WORD(data + 0x0E));
- printf("\n");
- printf("\tOEM-specific Information: 0x%08X\n",
+ pr_attr("OEM-specific Information", "0x%08X",
DWORD(data + 0x10));
if (h->length < 0x16) break;
- printf("\tNominal Value:");
- dmi_temperature_probe_value(WORD(data + 0x14));
- printf("\n");
+ dmi_temperature_probe_value("Nominal Value",
+ WORD(data + 0x14));
break;
case 29: /* 7.30 Electrical Current Probe */
- printf("Electrical Current Probe\n");
+ pr_handle_name("Electrical Current Probe");
if (h->length < 0x14) break;
- printf("\tDescription: %s\n",
+ pr_attr("Description", "%s",
dmi_string(h, data[0x04]));
- printf("\tLocation: %s\n",
+ pr_attr("Location", "%s",
dmi_voltage_probe_location(data[5] & 0x1F));
- printf("\tStatus: %s\n",
+ pr_attr("Status", "%s",
dmi_probe_status(data[0x05] >> 5));
- printf("\tMaximum Value:");
- dmi_current_probe_value(WORD(data + 0x06));
- printf("\n");
- printf("\tMinimum Value:");
- dmi_current_probe_value(WORD(data + 0x08));
- printf("\n");
- printf("\tResolution:");
+ dmi_current_probe_value("Maximum Value",
+ WORD(data + 0x06));
+ dmi_current_probe_value("Minimum Value",
+ WORD(data + 0x08));
dmi_current_probe_resolution(WORD(data + 0x0A));
- printf("\n");
- printf("\tTolerance:");
- dmi_current_probe_value(WORD(data + 0x0C));
- printf("\n");
- printf("\tAccuracy:");
+ dmi_current_probe_value("Tolerance",
+ WORD(data + 0x0C));
dmi_probe_accuracy(WORD(data + 0x0E));
- printf("\n");
- printf("\tOEM-specific Information: 0x%08X\n",
+ pr_attr("OEM-specific Information", "0x%08X",
DWORD(data + 0x10));
if (h->length < 0x16) break;
- printf("\tNominal Value:");
- dmi_current_probe_value(WORD(data + 0x14));
- printf("\n");
+ dmi_current_probe_value("Nominal Value",
+ WORD(data + 0x14));
break;
case 30: /* 7.31 Out-of-band Remote Access */
- printf("Out-of-band Remote Access\n");
+ pr_handle_name("Out-of-band Remote Access");
if (h->length < 0x06) break;
- printf("\tManufacturer Name: %s\n",
+ pr_attr("Manufacturer Name", "%s",
dmi_string(h, data[0x04]));
- printf("\tInbound Connection: %s\n",
+ pr_attr("Inbound Connection", "%s",
data[0x05] & (1 << 0) ? "Enabled" : "Disabled");
- printf("\tOutbound Connection: %s\n",
+ pr_attr("Outbound Connection", "%s",
data[0x05] & (1 << 1) ? "Enabled" : "Disabled");
break;
case 31: /* 7.32 Boot Integrity Services Entry Point */
- printf("Boot Integrity Services Entry Point\n");
+ pr_handle_name("Boot Integrity Services Entry Point");
if (h->length < 0x1C) break;
- printf("\tChecksum: %s\n",
+ pr_attr("Checksum", "%s",
checksum(data, h->length) ? "OK" : "Invalid");
- printf("\t16-bit Entry Point Address: %04X:%04X\n",
+ pr_attr("16-bit Entry Point Address", "%04X:%04X",
DWORD(data + 0x08) >> 16,
DWORD(data + 0x08) & 0xFFFF);
- printf("\t32-bit Entry Point Address: 0x%08X\n",
+ pr_attr("32-bit Entry Point Address", "0x%08X",
DWORD(data + 0x0C));
break;
case 32: /* 7.33 System Boot Information */
- printf("System Boot Information\n");
+ pr_handle_name("System Boot Information");
if (h->length < 0x0B) break;
- printf("\tStatus: %s\n",
+ pr_attr("Status", "%s",
dmi_system_boot_status(data[0x0A]));
break;
case 33: /* 7.34 64-bit Memory Error Information */
+ pr_handle_name("64-bit Memory Error Information");
if (h->length < 0x1F) break;
- printf("64-bit Memory Error Information\n");
- printf("\tType: %s\n",
+ pr_attr("Type", "%s",
dmi_memory_error_type(data[0x04]));
- printf("\tGranularity: %s\n",
+ pr_attr("Granularity", "%s",
dmi_memory_error_granularity(data[0x05]));
- printf("\tOperation: %s\n",
+ pr_attr("Operation", "%s",
dmi_memory_error_operation(data[0x06]));
- printf("\tVendor Syndrome:");
dmi_memory_error_syndrome(DWORD(data + 0x07));
- printf("\n");
- printf("\tMemory Array Address:");
- dmi_64bit_memory_error_address(QWORD(data + 0x0B));
- printf("\n");
- printf("\tDevice Address:");
- dmi_64bit_memory_error_address(QWORD(data + 0x13));
- printf("\n");
- printf("\tResolution:");
- dmi_32bit_memory_error_address(DWORD(data + 0x1B));
- printf("\n");
+ dmi_64bit_memory_error_address("Memory Array Address",
+ QWORD(data + 0x0B));
+ dmi_64bit_memory_error_address("Device Address",
+ QWORD(data + 0x13));
+ dmi_32bit_memory_error_address("Resolution",
+ DWORD(data + 0x1B));
break;
case 34: /* 7.35 Management Device */
- printf("Management Device\n");
+ pr_handle_name("Management Device");
if (h->length < 0x0B) break;
- printf("\tDescription: %s\n",
+ pr_attr("Description", "%s",
dmi_string(h, data[0x04]));
- printf("\tType: %s\n",
+ pr_attr("Type", "%s",
dmi_management_device_type(data[0x05]));
- printf("\tAddress: 0x%08X\n",
+ pr_attr("Address", "0x%08X",
DWORD(data + 0x06));
- printf("\tAddress Type: %s\n",
+ pr_attr("Address Type", "%s",
dmi_management_device_address_type(data[0x0A]));
break;
case 35: /* 7.36 Management Device Component */
- printf("Management Device Component\n");
+ pr_handle_name("Management Device Component");
if (h->length < 0x0B) break;
- printf("\tDescription: %s\n",
+ pr_attr("Description", "%s",
dmi_string(h, data[0x04]));
if (!(opt.flags & FLAG_QUIET))
{
- printf("\tManagement Device Handle: 0x%04X\n",
+ pr_attr("Management Device Handle", "0x%04X",
WORD(data + 0x05));
- printf("\tComponent Handle: 0x%04X\n",
+ pr_attr("Component Handle", "0x%04X",
WORD(data + 0x07));
if (WORD(data + 0x09) != 0xFFFF)
- printf("\tThreshold Handle: 0x%04X\n",
- WORD(data + 0x09));
+ pr_attr("Threshold Handle", "0x%04X",
+ WORD(data + 0x09));
}
break;
case 36: /* 7.37 Management Device Threshold Data */
- printf("Management Device Threshold Data\n");
+ pr_handle_name("Management Device Threshold Data");
if (h->length < 0x10) break;
if (WORD(data + 0x04) != 0x8000)
- printf("\tLower Non-critical Threshold: %d\n",
+ pr_attr("Lower Non-critical Threshold", "%d",
(i16)WORD(data + 0x04));
if (WORD(data + 0x06) != 0x8000)
- printf("\tUpper Non-critical Threshold: %d\n",
+ pr_attr("Upper Non-critical Threshold", "%d",
(i16)WORD(data + 0x06));
if (WORD(data + 0x08) != 0x8000)
- printf("\tLower Critical Threshold: %d\n",
+ pr_attr("Lower Critical Threshold", "%d",
(i16)WORD(data + 0x08));
if (WORD(data + 0x0A) != 0x8000)
- printf("\tUpper Critical Threshold: %d\n",
+ pr_attr("Upper Critical Threshold", "%d",
(i16)WORD(data + 0x0A));
if (WORD(data + 0x0C) != 0x8000)
- printf("\tLower Non-recoverable Threshold: %d\n",
+ pr_attr("Lower Non-recoverable Threshold", "%d",
(i16)WORD(data + 0x0C));
if (WORD(data + 0x0E) != 0x8000)
- printf("\tUpper Non-recoverable Threshold: %d\n",
+ pr_attr("Upper Non-recoverable Threshold", "%d",
(i16)WORD(data + 0x0E));
break;
case 37: /* 7.38 Memory Channel */
- printf("Memory Channel\n");
+ pr_handle_name("Memory Channel");
if (h->length < 0x07) break;
- printf("\tType: %s\n",
+ pr_attr("Type", "%s",
dmi_memory_channel_type(data[0x04]));
- printf("\tMaximal Load: %u\n",
+ pr_attr("Maximal Load", "%u",
data[0x05]);
- printf("\tDevices: %u\n",
+ pr_attr("Devices", "%u",
data[0x06]);
if (h->length < 0x07 + 3 * data[0x06]) break;
- dmi_memory_channel_devices(data[0x06], data + 0x07, "\t");
+ dmi_memory_channel_devices(data[0x06], data + 0x07);
break;
case 38: /* 7.39 IPMI Device Information */
@@ -4356,92 +5145,86 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
* We use the word "Version" instead of "Revision", conforming to
* the IPMI specification.
*/
- printf("IPMI Device Information\n");
+ pr_handle_name("IPMI Device Information");
if (h->length < 0x10) break;
- printf("\tInterface Type: %s\n",
+ pr_attr("Interface Type", "%s",
dmi_ipmi_interface_type(data[0x04]));
- printf("\tSpecification Version: %u.%u\n",
+ pr_attr("Specification Version", "%u.%u",
data[0x05] >> 4, data[0x05] & 0x0F);
- printf("\tI2C Slave Address: 0x%02x\n",
+ pr_attr("I2C Slave Address", "0x%02x",
data[0x06] >> 1);
if (data[0x07] != 0xFF)
- printf("\tNV Storage Device Address: %u\n",
+ pr_attr("NV Storage Device Address", "%u",
data[0x07]);
else
- printf("\tNV Storage Device: Not Present\n");
- printf("\tBase Address: ");
+ pr_attr("NV Storage Device", "Not Present");
dmi_ipmi_base_address(data[0x04], data + 0x08,
h->length < 0x11 ? 0 : (data[0x10] >> 4) & 1);
- printf("\n");
if (h->length < 0x12) break;
if (data[0x04] != 0x04)
{
- printf("\tRegister Spacing: %s\n",
+ pr_attr("Register Spacing", "%s",
dmi_ipmi_register_spacing(data[0x10] >> 6));
if (data[0x10] & (1 << 3))
{
- printf("\tInterrupt Polarity: %s\n",
+ pr_attr("Interrupt Polarity", "%s",
data[0x10] & (1 << 1) ? "Active High" : "Active Low");
- printf("\tInterrupt Trigger Mode: %s\n",
+ pr_attr("Interrupt Trigger Mode", "%s",
data[0x10] & (1 << 0) ? "Level" : "Edge");
}
}
if (data[0x11] != 0x00)
{
- printf("\tInterrupt Number: %u\n",
+ pr_attr("Interrupt Number", "%u",
data[0x11]);
}
break;
case 39: /* 7.40 System Power Supply */
- printf("System Power Supply\n");
+ pr_handle_name("System Power Supply");
if (h->length < 0x10) break;
if (data[0x04] != 0x00)
- printf("\tPower Unit Group: %u\n",
+ pr_attr("Power Unit Group", "%u",
data[0x04]);
- printf("\tLocation: %s\n",
+ pr_attr("Location", "%s",
dmi_string(h, data[0x05]));
- printf("\tName: %s\n",
+ pr_attr("Name", "%s",
dmi_string(h, data[0x06]));
- printf("\tManufacturer: %s\n",
+ pr_attr("Manufacturer", "%s",
dmi_string(h, data[0x07]));
- printf("\tSerial Number: %s\n",
+ pr_attr("Serial Number", "%s",
dmi_string(h, data[0x08]));
- printf("\tAsset Tag: %s\n",
+ pr_attr("Asset Tag", "%s",
dmi_string(h, data[0x09]));
- printf("\tModel Part Number: %s\n",
+ pr_attr("Model Part Number", "%s",
dmi_string(h, data[0x0A]));
- printf("\tRevision: %s\n",
+ pr_attr("Revision", "%s",
dmi_string(h, data[0x0B]));
- printf("\tMax Power Capacity:");
dmi_power_supply_power(WORD(data + 0x0C));
- printf("\n");
- printf("\tStatus:");
if (WORD(data + 0x0E) & (1 << 1))
- printf(" Present, %s",
+ pr_attr("Status", "Present, %s",
dmi_power_supply_status((WORD(data + 0x0E) >> 7) & 0x07));
else
- printf(" Not Present");
- printf("\n");
- printf("\tType: %s\n",
+ pr_attr("Status", "Not Present");
+ pr_attr("Type", "%s",
dmi_power_supply_type((WORD(data + 0x0E) >> 10) & 0x0F));
- printf("\tInput Voltage Range Switching: %s\n",
+ pr_attr("Input Voltage Range Switching", "%s",
dmi_power_supply_range_switching((WORD(data + 0x0E) >> 3) & 0x0F));
- printf("\tPlugged: %s\n",
+ pr_attr("Plugged", "%s",
WORD(data + 0x0E) & (1 << 2) ? "No" : "Yes");
- printf("\tHot Replaceable: %s\n",
+ pr_attr("Hot Replaceable", "%s",
WORD(data + 0x0E) & (1 << 0) ? "Yes" : "No");
if (h->length < 0x16) break;
if (!(opt.flags & FLAG_QUIET))
{
if (WORD(data + 0x10) != 0xFFFF)
- printf("\tInput Voltage Probe Handle: 0x%04X\n",
+ pr_attr("Input Voltage Probe Handle", "0x%04X",
WORD(data + 0x10));
if (WORD(data + 0x12) != 0xFFFF)
- printf("\tCooling Device Handle: 0x%04X\n",
+ pr_attr("Cooling Device Handle", "0x%04X",
WORD(data + 0x12));
if (WORD(data + 0x14) != 0xFFFF)
- printf("\tInput Current Probe Handle: 0x%04X\n",
+ pr_attr("Input Current Probe Handle", "0x%04X",
WORD(data + 0x14));
}
break;
@@ -4450,48 +5233,51 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
if (h->length < 0x0B) break;
if (opt.flags & FLAG_QUIET)
return;
- dmi_additional_info(h, "");
+ dmi_additional_info(h);
break;
case 41: /* 7.42 Onboard Device Extended Information */
- printf("Onboard Device\n");
+ pr_handle_name("Onboard Device");
if (h->length < 0x0B) break;
- printf("\tReference Designation: %s\n", dmi_string(h, data[0x04]));
- printf("\tType: %s\n",
+ pr_attr("Reference Designation", "%s", dmi_string(h, data[0x04]));
+ pr_attr("Type", "%s",
dmi_on_board_devices_type(data[0x05] & 0x7F));
- printf("\tStatus: %s\n",
+ pr_attr("Status", "%s",
data[0x05] & 0x80 ? "Enabled" : "Disabled");
- printf("\tType Instance: %u\n", data[0x06]);
- dmi_slot_segment_bus_func(WORD(data + 0x07), data[0x09], data[0x0A], "\t");
+ pr_attr("Type Instance", "%u", data[0x06]);
+ dmi_slot_segment_bus_func(WORD(data + 0x07), data[0x09], data[0x0A]);
break;
case 42: /* 7.43 Management Controller Host Interface */
- printf("Management Controller Host Interface\n");
- if (h->length < 0x05) break;
- printf("\tInterface Type: %s\n",
- dmi_management_controller_host_type(data[0x04]));
- /*
- * There you have a type-dependent, variable-length
- * part in the middle of the structure, with no
- * length specifier, so no easy way to decode the
- * common, final part of the structure. What a pity.
- */
- if (h->length < 0x09) break;
- if (data[0x04] == 0xF0) /* OEM */
+ pr_handle_name("Management Controller Host Interface");
+ if (ver < 0x0302)
{
- printf("\tVendor ID: 0x%02X%02X%02X%02X\n",
- data[0x05], data[0x06], data[0x07],
- data[0x08]);
+ if (h->length < 0x05) break;
+ pr_attr("Interface Type", "%s",
+ dmi_management_controller_host_type(data[0x04]));
+ /*
+ * There you have a type-dependent, variable-length
+ * part in the middle of the structure, with no
+ * length specifier, so no easy way to decode the
+ * common, final part of the structure. What a pity.
+ */
+ if (h->length < 0x09) break;
+ if (data[0x04] == 0xF0) /* OEM */
+ {
+ pr_attr("Vendor ID", "0x%02X%02X%02X%02X",
+ data[0x05], data[0x06], data[0x07],
+ data[0x08]);
+ }
}
+ else
+ dmi_parse_controller_structure(h);
break;
case 43: /* 7.44 TPM Device */
- printf("TPM Device\n");
+ pr_handle_name("TPM Device");
if (h->length < 0x1B) break;
- printf("\tVendor ID:");
dmi_tpm_vendor_id(data + 0x04);
- printf("\n");
- printf("\tSpecification Version: %d.%d", data[0x08], data[0x09]);
+ pr_attr("Specification Version", "%d.%d", data[0x08], data[0x09]);
switch (data[0x08])
{
case 0x01:
@@ -4500,13 +5286,13 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
* redundant with the above, and uncoded
* in a silly way.
*/
- printf("\tFirmware Revision: %u.%u\n",
+ pr_attr("Firmware Revision", "%u.%u",
data[0x0C], data[0x0D]);
break;
case 0x02:
- printf("\tFirmware Revision: %u.%u\n",
+ pr_attr("Firmware Revision", "%u.%u",
DWORD(data + 0x0A) >> 16,
- DWORD(data + 0x0A) && 0xFF);
+ DWORD(data + 0x0A) & 0xFFFF);
/*
* We skip the next 4 bytes, as their
* format is not standardized and their
@@ -4514,20 +5300,43 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
*/
break;
}
- printf("\tDescription: %s", dmi_string(h, data[0x12]));
- printf("\tCharacteristics:\n");
- dmi_tpm_characteristics(QWORD(data + 0x13), "\t\t");
+ pr_attr("Description", "%s", dmi_string(h, data[0x12]));
+ pr_list_start("Characteristics", NULL);
+ dmi_tpm_characteristics(QWORD(data + 0x13));
+ pr_list_end();
if (h->length < 0x1F) break;
- printf("\tOEM-specific Information: 0x%08X\n",
+ pr_attr("OEM-specific Information", "0x%08X",
DWORD(data + 0x1B));
break;
- case 126: /* 7.44 Inactive */
- printf("Inactive\n");
+ case 45: /* 7.46 Firmware Inventory Information */
+ pr_handle_name("Firmware Inventory Information");
+ if (h->length < 0x18) break;
+ pr_attr("Firmware Component Name", "%s",
+ dmi_string(h, data[0x04]));
+ pr_attr("Firmware Version", "%s",
+ dmi_string(h, data[0x05]));
+ pr_attr("Firmware ID", "%s", dmi_string(h, data[0x07]));
+ pr_attr("Release Date", "%s", dmi_string(h, data[0x09]));
+ pr_attr("Manufacturer", "%s", dmi_string(h, data[0x0A]));
+ pr_attr("Lowest Supported Firmware Version", "%s",
+ dmi_string(h, data[0x0B]));
+ dmi_memory_size("Image Size", QWORD(data + 0x0C));
+ pr_list_start("Characteristics", NULL);
+ dmi_firmware_characteristics(WORD(data + 0x14));
+ pr_list_end();
+ pr_attr("State", "%s", dmi_firmware_state(data[0x16]));
+ if (h->length < 0x18 + data[0x17] * 2) break;
+ if (!(opt.flags & FLAG_QUIET))
+ dmi_firmware_components(data[0x17], data + 0x18);
break;
- case 127: /* 7.45 End Of Table */
- printf("End Of Table\n");
+ case 126:
+ pr_handle_name("Inactive");
+ break;
+
+ case 127:
+ pr_handle_name("End Of Table");
break;
default:
@@ -4535,11 +5344,11 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
break;
if (opt.flags & FLAG_QUIET)
return;
- printf("%s Type\n",
+ pr_handle_name("%s Type",
h->type >= 128 ? "OEM-specific" : "Unknown");
- dmi_dump(h, "\t");
+ dmi_dump(h);
}
- printf("\n");
+ pr_sep();
}
static void to_dmi_header(struct dmi_header *h, u8 *data)
@@ -4576,9 +5385,16 @@ static void dmi_table_string(const struct dmi_header *h, const u8 *data, u16 ver
key = (opt.string->type << 8) | offset;
switch (key)
{
+ case 0x015: /* -s bios-revision */
+ if (data[offset - 1] != 0xFF && data[offset] != 0xFF)
+ printf("%u.%u\n", data[offset - 1], data[offset]);
+ break;
+ case 0x017: /* -s firmware-revision */
+ if (data[offset - 1] != 0xFF && data[offset] != 0xFF)
+ printf("%u.%u\n", data[offset - 1], data[offset]);
+ break;
case 0x108:
- dmi_system_uuid(data + offset, ver);
- printf("\n");
+ dmi_system_uuid(NULL, NULL, data + offset, ver);
break;
case 0x305:
printf("%s\n", dmi_chassis_type(data[offset]));
@@ -4587,19 +5403,72 @@ static void dmi_table_string(const struct dmi_header *h, const u8 *data, u16 ver
printf("%s\n", dmi_processor_family(h, ver));
break;
case 0x416:
- dmi_processor_frequency(data + offset);
- printf("\n");
+ dmi_processor_frequency(NULL, data + offset);
break;
default:
printf("%s\n", dmi_string(h, data[offset]));
}
}
-static void dmi_table_dump(const u8 *buf, u32 len)
+static int dmi_table_dump(const u8 *ep, u32 ep_len, const u8 *table,
+ u32 table_len)
{
+ int fd;
+ FILE *f;
+
+ fd = open(opt.dumpfile, O_WRONLY|O_CREAT|O_EXCL, 0666);
+ if (fd == -1)
+ {
+ fprintf(stderr, "%s: ", opt.dumpfile);
+ perror("open");
+ return -1;
+ }
+
+ f = fdopen(fd, "wb");
+ if (!f)
+ {
+ fprintf(stderr, "%s: ", opt.dumpfile);
+ perror("fdopen");
+ return -1;
+ }
+
if (!(opt.flags & FLAG_QUIET))
- printf("# Writing %d bytes to %s.\n", len, opt.dumpfile);
- write_dump(32, len, buf, opt.dumpfile, 0);
+ pr_comment("Writing %d bytes to %s.", ep_len, opt.dumpfile);
+ if (fwrite(ep, ep_len, 1, f) != 1)
+ {
+ fprintf(stderr, "%s: ", opt.dumpfile);
+ perror("fwrite");
+ goto err_close;
+ }
+
+ if (fseek(f, 32, SEEK_SET) != 0)
+ {
+ fprintf(stderr, "%s: ", opt.dumpfile);
+ perror("fseek");
+ goto err_close;
+ }
+
+ if (!(opt.flags & FLAG_QUIET))
+ pr_comment("Writing %d bytes to %s.", table_len, opt.dumpfile);
+ if (fwrite(table, table_len, 1, f) != 1)
+ {
+ fprintf(stderr, "%s: ", opt.dumpfile);
+ perror("fwrite");
+ goto err_close;
+ }
+
+ if (fclose(f))
+ {
+ fprintf(stderr, "%s: ", opt.dumpfile);
+ perror("fclose");
+ return -1;
+ }
+
+ return 0;
+
+err_close:
+ fclose(f);
+ return -1;
}
static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
@@ -4607,6 +5476,51 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
u8 *data;
int i = 0;
+ /* First pass: Save specific values needed to decode OEM types */
+ data = buf;
+ while ((i < num || !num)
+ && data + 4 <= buf + len) /* 4 is the length of an SMBIOS structure header */
+ {
+ u8 *next;
+ struct dmi_header h;
+
+ to_dmi_header(&h, data);
+
+ /*
+ * If a short entry is found (less than 4 bytes), not only it
+ * is invalid, but we cannot reliably locate the next entry.
+ * Also stop at end-of-table marker if so instructed.
+ */
+ if (h.length < 4 ||
+ (h.type == 127 &&
+ (opt.flags & (FLAG_QUIET | FLAG_STOP_AT_EOT))))
+ break;
+ i++;
+
+ /* Look for the next handle */
+ next = data + h.length;
+ while ((unsigned long)(next - buf + 1) < len
+ && (next[0] != 0 || next[1] != 0))
+ next++;
+ next += 2;
+
+ /* Make sure the whole structure fits in the table */
+ if ((unsigned long)(next - buf) > len)
+ break;
+
+ /* Assign vendor for vendor-specific decodes later */
+ if (h.type == 1 && h.length >= 6)
+ dmi_set_vendor(_dmi_string(&h, data[0x04], 0),
+ _dmi_string(&h, data[0x05], 0));
+
+ /* Remember CPUID type for HPE type 199 */
+ if (h.type == 4 && h.length >= 0x1A && cpuid_type == cpuid_none)
+ cpuid_type = dmi_get_cpuid_type(&h);
+ data = next;
+ }
+
+ /* Second pass: Actually decode the data */
+ i = 0;
data = buf;
while ((i < num || !num)
&& data + 4 <= buf + len) /* 4 is the length of an SMBIOS structure header */
@@ -4617,6 +5531,7 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
to_dmi_header(&h, data);
display = ((opt.type == NULL || opt.type[h.type])
+ && (opt.handle == ~0U || opt.handle == h.handle)
&& !((opt.flags & FLAG_QUIET) && (h.type == 126 || h.type == 127))
&& !opt.string);
@@ -4638,6 +5553,7 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
}
break;
}
+ i++;
/* In quiet mode, stop decoding at end of table marker */
if ((opt.flags & FLAG_QUIET) && h.type == 127)
@@ -4645,44 +5561,44 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
if (display
&& (!(opt.flags & FLAG_QUIET) || (opt.flags & FLAG_DUMP)))
- printf("Handle 0x%04X, DMI type %d, %d bytes\n",
- h.handle, h.type, h.length);
-
- /* assign vendor for vendor-specific decodes later */
- if (h.type == 1 && h.length >= 5)
- dmi_set_vendor(dmi_string(&h, data[0x04]));
-
- /* Fixup a common mistake */
- if (h.type == 34)
- dmi_fixup_type_34(&h, display);
+ pr_handle(&h);
- /* look for the next handle */
+ /* Look for the next handle */
next = data + h.length;
while ((unsigned long)(next - buf + 1) < len
&& (next[0] != 0 || next[1] != 0))
next++;
next += 2;
+
+ /* Make sure the whole structure fits in the table */
+ if ((unsigned long)(next - buf) > len)
+ {
+ if (display && !(opt.flags & FLAG_QUIET))
+ pr_struct_err("<TRUNCATED>");
+ pr_sep();
+ data = next;
+ break;
+ }
+
+ /* Fixup a common mistake */
+ if (h.type == 34 && !(opt.flags & FLAG_NO_QUIRKS))
+ dmi_fixup_type_34(&h, display);
+
if (display)
{
- if ((unsigned long)(next - buf) <= len)
+ if (opt.flags & FLAG_DUMP)
{
- if (opt.flags & FLAG_DUMP)
- {
- dmi_dump(&h, "\t");
- printf("\n");
- }
- else
- dmi_decode(&h, ver);
+ dmi_dump(&h);
+ pr_sep();
}
- else if (!(opt.flags & FLAG_QUIET))
- printf("\t<TRUNCATED>\n\n");
+ else
+ dmi_decode(&h, ver);
}
else if (opt.string != NULL
&& opt.string->type == h.type)
dmi_table_string(&h, data, ver);
data = next;
- i++;
/* SMBIOS v3 requires stopping at this marker */
if (h.type == 127 && (flags & FLAG_STOP_AT_EOT))
@@ -4706,18 +5622,19 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
}
}
-static void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem,
- u32 flags)
+/* Allocates a buffer for the table, must be freed by the caller */
+static u8 *dmi_table_get(off_t base, u32 *len, u16 num, u32 ver,
+ const char *devmem, u32 flags)
{
u8 *buf;
if (ver > SUPPORTED_SMBIOS_VER && !(opt.flags & FLAG_QUIET))
{
- printf("# SMBIOS implementations newer than version %u.%u.%u are not\n"
- "# fully supported by this version of dmidecode.\n",
- SUPPORTED_SMBIOS_VER >> 16,
- (SUPPORTED_SMBIOS_VER >> 8) & 0xFF,
- SUPPORTED_SMBIOS_VER & 0xFF);
+ pr_comment("SMBIOS implementations newer than version %u.%u.%u are not",
+ SUPPORTED_SMBIOS_VER >> 16,
+ (SUPPORTED_SMBIOS_VER >> 8) & 0xFF,
+ SUPPORTED_SMBIOS_VER & 0xFF);
+ pr_comment("fully supported by this version of dmidecode.");
}
if (!(opt.flags & FLAG_QUIET))
@@ -4725,13 +5642,13 @@ static void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem,
if (opt.type == NULL)
{
if (num)
- printf("%u structures occupying %u bytes.\n",
- num, len);
+ pr_info("%u structures occupying %u bytes.",
+ num, *len);
if (!(opt.flags & FLAG_FROM_DUMP))
- printf("Table at 0x%08llX.\n",
- (unsigned long long)base);
+ pr_info("Table at 0x%08llX.",
+ (unsigned long long)base);
}
- printf("\n");
+ pr_sep();
}
if ((flags & FLAG_NO_FILE_OFFSET) || (opt.flags & FLAG_FROM_DUMP))
@@ -4744,19 +5661,19 @@ static void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem,
* would be the result of the kernel truncating the table on
* parse error.
*/
- size_t size = len;
+ size_t size = *len;
buf = read_file(flags & FLAG_NO_FILE_OFFSET ? 0 : base,
&size, devmem);
- if (!(opt.flags & FLAG_QUIET) && num && size != (size_t)len)
+ if (!(opt.flags & FLAG_QUIET) && num && size != (size_t)*len)
{
fprintf(stderr, "Wrong DMI structures length: %u bytes "
"announced, only %lu bytes available.\n",
- len, (unsigned long)size);
+ *len, (unsigned long)size);
}
- len = size;
+ *len = size;
}
else
- buf = mem_chunk(base, len, devmem);
+ buf = mem_chunk(base, *len, devmem);
if (buf == NULL)
{
@@ -4766,15 +5683,9 @@ static void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem,
fprintf(stderr,
"Try compiling dmidecode with -DUSE_MMAP.\n");
#endif
- return;
}
- if (opt.flags & FLAG_DUMP_BIN)
- dmi_table_dump(buf, len);
- else
- dmi_table_decode(buf, len, num, ver >> 8, flags);
-
- free(buf);
+ return buf;
}
@@ -4809,16 +5720,27 @@ static void overwrite_smbios3_address(u8 *buf)
static int smbios3_decode(u8 *buf, const char *devmem, u32 flags)
{
- u32 ver;
+ u32 ver, len;
u64 offset;
+ u8 *table;
- if (!checksum(buf, buf[0x06]))
+ /* Don't let checksum run beyond the buffer */
+ if (buf[0x06] > 0x20)
+ {
+ fprintf(stderr,
+ "Entry point length too large (%u bytes, expected %u).\n",
+ (unsigned int)buf[0x06], 0x18U);
+ return 0;
+ }
+
+ if (buf[0x06] < 0x18
+ || !checksum(buf, buf[0x06]))
return 0;
ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09];
if (!(opt.flags & FLAG_QUIET))
- printf("SMBIOS %u.%u.%u present.\n",
- buf[0x07], buf[0x08], buf[0x09]);
+ pr_info("SMBIOS %u.%u.%u present.",
+ buf[0x07], buf[0x08], buf[0x09]);
offset = QWORD(buf + 0x10);
if (!(flags & FLAG_NO_FILE_OFFSET) && offset.h && sizeof(off_t) < 8)
@@ -4827,8 +5749,12 @@ static int smbios3_decode(u8 *buf, const char *devmem, u32 flags)
return 0;
}
- dmi_table(((off_t)offset.h << 32) | offset.l,
- DWORD(buf + 0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT);
+ /* Maximum length, may get trimmed */
+ len = DWORD(buf + 0x0C);
+ table = dmi_table_get(((off_t)offset.h << 32) | offset.l, &len, 0, ver,
+ devmem, flags | FLAG_STOP_AT_EOT);
+ if (table == NULL)
+ return 1;
if (opt.flags & FLAG_DUMP_BIN)
{
@@ -4837,50 +5763,81 @@ static int smbios3_decode(u8 *buf, const char *devmem, u32 flags)
memcpy(crafted, buf, 32);
overwrite_smbios3_address(crafted);
- if (!(opt.flags & FLAG_QUIET))
- printf("# Writing %d bytes to %s.\n", crafted[0x06],
- opt.dumpfile);
- write_dump(0, crafted[0x06], crafted, opt.dumpfile, 1);
+ dmi_table_dump(crafted, crafted[0x06], table, len);
}
+ else
+ {
+ dmi_table_decode(table, len, 0, ver >> 8,
+ flags | FLAG_STOP_AT_EOT);
+ }
+
+ free(table);
return 1;
}
-static int smbios_decode(u8 *buf, const char *devmem, u32 flags)
+static void dmi_fixup_version(u16 *ver)
{
- u16 ver;
-
- if (!checksum(buf, buf[0x05])
- || memcmp(buf + 0x10, "_DMI_", 5) != 0
- || !checksum(buf + 0x10, 0x0F))
- return 0;
-
- ver = (buf[0x06] << 8) + buf[0x07];
/* Some BIOS report weird SMBIOS version, fix that up */
- switch (ver)
+ switch (*ver)
{
case 0x021F:
case 0x0221:
if (!(opt.flags & FLAG_QUIET))
fprintf(stderr,
"SMBIOS version fixup (2.%d -> 2.%d).\n",
- ver & 0xFF, 3);
- ver = 0x0203;
+ *ver & 0xFF, 3);
+ *ver = 0x0203;
break;
case 0x0233:
if (!(opt.flags & FLAG_QUIET))
fprintf(stderr,
"SMBIOS version fixup (2.%d -> 2.%d).\n",
51, 6);
- ver = 0x0206;
+ *ver = 0x0206;
break;
}
+}
+
+static int smbios_decode(u8 *buf, const char *devmem, u32 flags)
+{
+ u16 ver, num;
+ u32 len;
+ u8 *table;
+
+ /* Don't let checksum run beyond the buffer */
+ if (buf[0x05] > 0x20)
+ {
+ fprintf(stderr,
+ "Entry point length too large (%u bytes, expected %u).\n",
+ (unsigned int)buf[0x05], 0x1FU);
+ return 0;
+ }
+
+ /*
+ * The size of this structure is 0x1F bytes, but we also accept value
+ * 0x1E due to a mistake in SMBIOS specification version 2.1.
+ */
+ if (buf[0x05] < 0x1E
+ || !checksum(buf, buf[0x05])
+ || memcmp(buf + 0x10, "_DMI_", 5) != 0
+ || !checksum(buf + 0x10, 0x0F))
+ return 0;
+
+ ver = (buf[0x06] << 8) + buf[0x07];
+ if (!(opt.flags & FLAG_NO_QUIRKS))
+ dmi_fixup_version(&ver);
if (!(opt.flags & FLAG_QUIET))
- printf("SMBIOS %u.%u present.\n",
+ pr_info("SMBIOS %u.%u present.",
ver >> 8, ver & 0xFF);
- dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C),
- ver << 8, devmem, flags);
+ /* Maximum length, may get trimmed */
+ len = WORD(buf + 0x16);
+ num = WORD(buf + 0x1C);
+ table = dmi_table_get(DWORD(buf + 0x18), &len, num, ver << 8,
+ devmem, flags);
+ if (table == NULL)
+ return 1;
if (opt.flags & FLAG_DUMP_BIN)
{
@@ -4889,27 +5846,39 @@ static int smbios_decode(u8 *buf, const char *devmem, u32 flags)
memcpy(crafted, buf, 32);
overwrite_dmi_address(crafted + 0x10);
- if (!(opt.flags & FLAG_QUIET))
- printf("# Writing %d bytes to %s.\n", crafted[0x05],
- opt.dumpfile);
- write_dump(0, crafted[0x05], crafted, opt.dumpfile, 1);
+ dmi_table_dump(crafted, crafted[0x05], table, len);
}
+ else
+ {
+ dmi_table_decode(table, len, num, ver, flags);
+ }
+
+ free(table);
return 1;
}
static int legacy_decode(u8 *buf, const char *devmem, u32 flags)
{
+ u16 ver, num;
+ u32 len;
+ u8 *table;
+
if (!checksum(buf, 0x0F))
return 0;
+ ver = ((buf[0x0E] & 0xF0) << 4) + (buf[0x0E] & 0x0F);
if (!(opt.flags & FLAG_QUIET))
- printf("Legacy DMI %u.%u present.\n",
+ pr_info("Legacy DMI %u.%u present.",
buf[0x0E] >> 4, buf[0x0E] & 0x0F);
- dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C),
- ((buf[0x0E] & 0xF0) << 12) + ((buf[0x0E] & 0x0F) << 8),
- devmem, flags);
+ /* Maximum length, may get trimmed */
+ len = WORD(buf + 0x06);
+ num = WORD(buf + 0x0C);
+ table = dmi_table_get(DWORD(buf + 0x08), &len, num, ver << 8,
+ devmem, flags);
+ if (table == NULL)
+ return 1;
if (opt.flags & FLAG_DUMP_BIN)
{
@@ -4918,12 +5887,15 @@ static int legacy_decode(u8 *buf, const char *devmem, u32 flags)
memcpy(crafted, buf, 16);
overwrite_dmi_address(crafted);
- if (!(opt.flags & FLAG_QUIET))
- printf("# Writing %d bytes to %s.\n", 0x0F,
- opt.dumpfile);
- write_dump(0, 0x0F, crafted, opt.dumpfile, 1);
+ dmi_table_dump(crafted, 0x0F, table, len);
+ }
+ else
+ {
+ dmi_table_decode(table, len, num, ver, flags);
}
+ free(table);
+
return 1;
}
@@ -4934,13 +5906,19 @@ static int legacy_decode(u8 *buf, const char *devmem, u32 flags)
#define EFI_NO_SMBIOS (-2)
static int address_from_efi(off_t *address)
{
+#if defined(__linux__)
FILE *efi_systab;
const char *filename;
char linebuf[64];
+#elif defined(__FreeBSD__)
+ char addrstr[KENV_MVALLEN + 1];
+#endif
+ const char *eptype;
int ret;
*address = 0; /* Prevent compiler warning */
+#if defined(__linux__)
/*
* Linux up to 2.6.6: /proc/efi/systab
* Linux 2.6.7 and up: /sys/firmware/efi/systab
@@ -4960,9 +5938,7 @@ static int address_from_efi(off_t *address)
|| strcmp(linebuf, "SMBIOS") == 0)
{
*address = strtoull(addrp, NULL, 0);
- if (!(opt.flags & FLAG_QUIET))
- printf("# %s entry point at 0x%08llx\n",
- linebuf, (unsigned long long)*address);
+ eptype = linebuf;
ret = 0;
break;
}
@@ -4972,6 +5948,31 @@ static int address_from_efi(off_t *address)
if (ret == EFI_NO_SMBIOS)
fprintf(stderr, "%s: SMBIOS entry point missing\n", filename);
+#elif defined(__FreeBSD__)
+ /*
+ * On FreeBSD, SMBIOS anchor base address in UEFI mode is exposed
+ * via kernel environment:
+ * https://svnweb.freebsd.org/base?view=revision&revision=307326
+ */
+ ret = kenv(KENV_GET, "hint.smbios.0.mem", addrstr, sizeof(addrstr));
+ if (ret == -1)
+ {
+ if (errno != ENOENT)
+ perror("kenv");
+ return EFI_NOT_FOUND;
+ }
+
+ *address = strtoull(addrstr, NULL, 0);
+ eptype = "SMBIOS";
+ ret = 0;
+#else
+ ret = EFI_NOT_FOUND;
+#endif
+
+ if (ret == 0 && !(opt.flags & FLAG_QUIET))
+ pr_comment("%s entry point at 0x%08llx",
+ eptype, (unsigned long long)*address);
+
return ret;
}
@@ -4982,7 +5983,7 @@ int main(int argc, char * const argv[])
off_t fp;
size_t size;
int efi;
- u8 *buf;
+ u8 *buf = NULL;
/*
* We don't want stdout and stderr to be mixed up if both are
@@ -5000,6 +6001,7 @@ int main(int argc, char * const argv[])
/* Set default option values */
opt.devmem = DEFAULT_MEM_DEV;
opt.flags = 0;
+ opt.handle = ~0U;
if (parse_command_line(argc, argv)<0)
{
@@ -5020,14 +6022,14 @@ int main(int argc, char * const argv[])
}
if (!(opt.flags & FLAG_QUIET))
- printf("# dmidecode %s\n", VERSION);
+ pr_comment("dmidecode %s", VERSION);
/* Read from dump if so instructed */
if (opt.flags & FLAG_FROM_DUMP)
{
if (!(opt.flags & FLAG_QUIET))
- printf("Reading SMBIOS/DMI data from file %s.\n",
- opt.dumpfile);
+ pr_info("Reading SMBIOS/DMI data from file %s.",
+ opt.dumpfile);
if ((buf = mem_chunk(0, 0x20, opt.dumpfile)) == NULL)
{
ret = 1;
@@ -5062,7 +6064,7 @@ int main(int argc, char * const argv[])
&& (buf = read_file(0, &size, SYS_ENTRY_FILE)) != NULL)
{
if (!(opt.flags & FLAG_QUIET))
- printf("Getting SMBIOS data from sysfs.\n");
+ pr_info("Getting SMBIOS data from sysfs.");
if (size >= 24 && memcmp(buf, "_SM3_", 5) == 0)
{
if (smbios3_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET))
@@ -5082,10 +6084,10 @@ int main(int argc, char * const argv[])
if (found)
goto done;
if (!(opt.flags & FLAG_QUIET))
- printf("Failed to get SMBIOS data from sysfs.\n");
+ pr_info("Failed to get SMBIOS data from sysfs.");
}
- /* Next try EFI (ia64, Intel-based Mac) */
+ /* Next try EFI (ia64, Intel-based Mac, arm64) */
efi = address_from_efi(&fp);
switch (efi)
{
@@ -5097,8 +6099,8 @@ int main(int argc, char * const argv[])
}
if (!(opt.flags & FLAG_QUIET))
- printf("Found SMBIOS entry point in EFI, reading table from %s.\n",
- opt.devmem);
+ pr_info("Found SMBIOS entry point in EFI, reading table from %s.",
+ opt.devmem);
if ((buf = mem_chunk(fp, 0x20, opt.devmem)) == NULL)
{
ret = 1;
@@ -5118,8 +6120,9 @@ int main(int argc, char * const argv[])
goto done;
memory_scan:
+#if defined __i386__ || defined __x86_64__
if (!(opt.flags & FLAG_QUIET))
- printf("Scanning %s for entry point.\n", opt.devmem);
+ pr_info("Scanning %s for entry point.", opt.devmem);
/* Fallback to memory scan (x86, x86_64) */
if ((buf = mem_chunk(0xF0000, 0x10000, opt.devmem)) == NULL)
{
@@ -5160,10 +6163,11 @@ memory_scan:
}
}
}
+#endif
done:
if (!found && !(opt.flags & FLAG_QUIET))
- printf("# No SMBIOS nor DMI entry point found, sorry.\n");
+ pr_comment("No SMBIOS nor DMI entry point found, sorry.");
free(buf);
exit_free:
diff --git a/dmidecode.h b/dmidecode.h
index 20e7e96..318cdc6 100644
--- a/dmidecode.h
+++ b/dmidecode.h
@@ -1,7 +1,7 @@
/*
* This file is part of the dmidecode project.
*
- * Copyright (C) 2005-2008 Jean Delvare <jdelvare@suse.de>
+ * Copyright (C) 2005-2020 Jean Delvare <jdelvare@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,6 +18,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef DMIDECODE_H
+#define DMIDECODE_H
+
#include "types.h"
struct dmi_header
@@ -28,5 +31,23 @@ struct dmi_header
u8 *data;
};
+enum cpuid_type
+{
+ cpuid_none,
+ cpuid_80386,
+ cpuid_80486,
+ cpuid_arm_legacy,
+ cpuid_arm_soc_id,
+ cpuid_x86_intel,
+ cpuid_x86_amd,
+};
+
+extern enum cpuid_type cpuid_type;
+
int is_printable(const u8 *data, int len);
const char *dmi_string(const struct dmi_header *dm, u8 s);
+void dmi_print_memory_size(const char *addr, u64 code, int shift);
+void dmi_print_cpuid(void (*print_cb)(const char *name, const char *format, ...),
+ const char *label, enum cpuid_type sig, const u8 *p);
+
+#endif
diff --git a/dmioem.c b/dmioem.c
index 034ad9f..dc4b857 100644
--- a/dmioem.c
+++ b/dmioem.c
@@ -2,7 +2,7 @@
* Decoding of OEM-specific entries
* This file is part of the dmidecode project.
*
- * Copyright (C) 2007-2008 Jean Delvare <jdelvare@suse.de>
+ * Copyright (C) 2007-2020 Jean Delvare <jdelvare@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,8 +23,11 @@
#include <string.h>
#include "types.h"
+#include "util.h"
#include "dmidecode.h"
#include "dmioem.h"
+#include "dmiopt.h"
+#include "dmioutput.h"
/*
* Globals for vendor-specific decodes
@@ -33,37 +36,100 @@
enum DMI_VENDORS
{
VENDOR_UNKNOWN,
- VENDOR_HP,
VENDOR_ACER,
+ VENDOR_HP,
+ VENDOR_HPE,
+ VENDOR_IBM,
+ VENDOR_LENOVO,
};
static enum DMI_VENDORS dmi_vendor = VENDOR_UNKNOWN;
+static const char *dmi_product = NULL;
/*
* Remember the system vendor for later use. We only actually store the
* value if we know how to decode at least one specific entry type for
* that vendor.
*/
-void dmi_set_vendor(const char *s)
+void dmi_set_vendor(const char *v, const char *p)
{
- int len;
+ const struct { const char *str; enum DMI_VENDORS id; } vendor[] = {
+ { "Acer", VENDOR_ACER },
+ { "HP", VENDOR_HP },
+ { "Hewlett-Packard", VENDOR_HP },
+ { "HPE", VENDOR_HPE },
+ { "Hewlett Packard Enterprise", VENDOR_HPE },
+ { "IBM", VENDOR_IBM },
+ { "LENOVO", VENDOR_LENOVO },
+ };
+ unsigned int i;
+ size_t len;
/*
* Often DMI strings have trailing spaces. Ignore these
* when checking for known vendor names.
*/
- len = strlen(s);
- while (len && s[len - 1] == ' ')
+ len = v ? strlen(v) : 0;
+ while (len && v[len - 1] == ' ')
len--;
- if (strncmp(s, "HP", len) == 0 || strncmp(s, "Hewlett-Packard", len) == 0)
- dmi_vendor = VENDOR_HP;
- else if (strncmp(s, "Acer", len) == 0)
- dmi_vendor = VENDOR_ACER;
+ for (i = 0; i < ARRAY_SIZE(vendor); i++)
+ {
+ if (strlen(vendor[i].str) == len &&
+ strncmp(v, vendor[i].str, len) == 0)
+ {
+ dmi_vendor = vendor[i].id;
+ break;
+ }
+ }
+
+ dmi_product = p;
+}
+
+/*
+ * Acer-specific data structures are decoded here.
+ */
+
+static int dmi_decode_acer(const struct dmi_header *h)
+{
+ u8 *data = h->data;
+ u16 cap;
+
+ switch (h->type)
+ {
+ case 170:
+ /*
+ * Vendor Specific: Acer Hotkey Function
+ *
+ * Source: acer-wmi kernel driver
+ *
+ * Probably applies to some laptop models of other
+ * brands, including Fujitsu-Siemens, Medion, Lenovo,
+ * and eMachines.
+ */
+ pr_handle_name("Acer Hotkey Function");
+ if (h->length < 0x0F) break;
+ cap = WORD(data + 0x04);
+ pr_attr("Function bitmap for Communication Button", "0x%04hx", cap);
+ pr_subattr("WiFi", "%s", cap & 0x0001 ? "Yes" : "No");
+ pr_subattr("3G", "%s", cap & 0x0040 ? "Yes" : "No");
+ pr_subattr("WiMAX", "%s", cap & 0x0080 ? "Yes" : "No");
+ pr_subattr("Bluetooth", "%s", cap & 0x0800 ? "Yes" : "No");
+ pr_attr("Function bitmap for Application Button", "0x%04hx", WORD(data + 0x06));
+ pr_attr("Function bitmap for Media Button", "0x%04hx", WORD(data + 0x08));
+ pr_attr("Function bitmap for Display Button", "0x%04hx", WORD(data + 0x0A));
+ pr_attr("Function bitmap for Others Button", "0x%04hx", WORD(data + 0x0C));
+ pr_attr("Communication Function Key Number", "%d", data[0x0E]);
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
}
/*
- * HP-specific data structures are decoded here.
+ * HPE-specific data structures are decoded here.
*
* Code contributed by John Cagle and Tyler Bell.
*/
@@ -76,50 +142,700 @@ static void dmi_print_hp_net_iface_rec(u8 id, u8 bus, u8 dev, const u8 *mac)
* 640K ought to be enough for anybody(said no one, ever).
* */
static u8 nic_ctr;
+ char attr[8];
if (id == 0xFF)
id = ++nic_ctr;
+ sprintf(attr, "NIC %hhu", id);
if (dev == 0x00 && bus == 0x00)
- printf("\tNIC %d: Disabled\n", id);
+ pr_attr(attr, "Disabled");
else if (dev == 0xFF && bus == 0xFF)
- printf("\tNIC %d: Not Installed\n", id);
+ pr_attr(attr, "Not Installed");
else
{
- printf("\tNIC %d: PCI device %02x:%02x.%x, "
- "MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
- id, bus, dev >> 3, dev & 7,
+ pr_attr(attr, "PCI device %02x:%02x.%x, "
+ "MAC address %02X:%02X:%02X:%02X:%02X:%02X",
+ bus, dev >> 3, dev & 7,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
}
+typedef enum { G6 = 6, G7, G8, G9, G10, G10P } dmi_hpegen_t;
+
+static int dmi_hpegen(const char *s)
+{
+ struct { const char *name; dmi_hpegen_t gen; } table[] = {
+ { "Gen10 Plus", G10P },
+ { "Gen10", G10 },
+ { "Gen9", G9 },
+ { "Gen8", G8 },
+ { "G7", G7 },
+ { "G6", G6 },
+ };
+ unsigned int i;
+
+ if (!strstr(s, "ProLiant") && !strstr(s, "Apollo") &&
+ !strstr(s, "Synergy") && !strstr(s, "Edgeline"))
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE(table); i++) {
+ if (strstr(s, table[i].name))
+ return(table[i].gen);
+ }
+
+ return (dmi_vendor == VENDOR_HPE) ? G10P : G6;
+}
+
+static void dmi_hp_240_attr(u64 defined, u64 set)
+{
+ static const char *attributes[] = {
+ "Updatable",
+ "Reset Required",
+ "Authentication Required",
+ "In Use",
+ "UEFI Image",
+ };
+ unsigned int i;
+
+ pr_list_start("Attributes Defined/Set", NULL);
+ for (i = 0; i < ARRAY_SIZE(attributes); i++)
+ {
+ if (!(defined.l & (1UL << i)))
+ continue;
+ pr_list_item("%s: %s", attributes[i], set.l & (1UL << i) ? "Yes" : "No");
+ }
+ pr_list_end();
+}
+
+static void dmi_hp_203_assoc_hndl(const char *fname, u16 num)
+{
+ if (opt.flags & FLAG_QUIET)
+ return;
+
+ if (num == 0xFFFE)
+ pr_attr(fname, "N/A");
+ else
+ pr_attr(fname, "0x%04X", num);
+}
+
+static void dmi_hp_203_pciinfo(const char *fname, u16 num)
+{
+ if (num == 0xFFFF)
+ pr_attr(fname, "Device Not Present");
+ else
+ pr_attr(fname, "0x%04x", num);
+}
+
+static void dmi_hp_203_bayenc(const char *fname, u8 num)
+{
+ switch (num)
+ {
+ case 0x00:
+ pr_attr(fname, "Unknown");
+ break;
+ case 0xff:
+ pr_attr(fname, "Do Not Display");
+ break;
+ default:
+ pr_attr(fname, "%d", num);
+ }
+}
+
+static void dmi_hp_203_devtyp(const char *fname, unsigned int code)
+{
+ const char *str = "Reserved";
+ static const char *type[] = {
+ "Unknown", /* 0x00 */
+ "Reserved",
+ "Reserved",
+ "Flexible LOM",
+ "Embedded LOM",
+ "NIC in a Slot",
+ "Storage Controller",
+ "Smart Array Storage Controller",
+ "USB Hard Disk",
+ "Other PCI Device",
+ "RAM Disk",
+ "Firmware Volume",
+ "UEFI Shell",
+ "Generic UEFI USB Boot Entry",
+ "Dynamic Smart Array Controller",
+ "File",
+ "NVME Hard Drive",
+ "NVDIMM" /* 0x11 */
+ };
+
+ if (code < ARRAY_SIZE(type))
+ str = type[code];
+
+ pr_attr(fname, "%s", str);
+}
+
+static void dmi_hp_203_devloc(const char *fname, unsigned int code)
+{
+ const char *str = "Reserved";
+ static const char *location[] = {
+ "Unknown", /* 0x00 */
+ "Embedded",
+ "iLO Virtual Media",
+ "Front USB Port",
+ "Rear USB Port",
+ "Internal USB",
+ "Internal SD Card",
+ "Internal Virtual USB (Embedded NAND)",
+ "Embedded SATA Port",
+ "Embedded Smart Array",
+ "PCI Slot",
+ "RAM Memory",
+ "USB",
+ "Dynamic Smart Array Controller",
+ "URL",
+ "NVMe Drive Bay" /* 0x0F */
+ };
+
+ if (code < ARRAY_SIZE(location))
+ str = location[code];
+
+ pr_attr(fname, "%s", str);
+}
+
+static void dmi_hp_216_fw_type(u16 code)
+{
+ const char *str = "Reserved";
+ static const char * const type[] = {
+ "Reserved", /* 0x00 */
+ "System ROM",
+ "Redundant System ROM",
+ "System ROM Bootblock",
+ "Power Management Controller Firmware",
+ "Power Management Controller Firmware Bootloader",
+ "SL Chassis Firmware",
+ "SL Chassis Firmware Bootloader",
+ "Hardware PAL/CPLD",
+ "SPS Firmware (ME Firmware)",
+ "SL Chassis PAL/CPLD",
+ "Compatibility Support Module (CSM)",
+ "APML",
+ "Smart Storage Battery (Megacell) Firmware",
+ "Trusted Module (TPM or TCM) Firmware Version",
+ "NVMe Backplane Firmware",
+ "Intelligent Provisioning",
+ "SPI Descriptor Version",
+ "Innovation Engine Firmware (IE Firmware)",
+ "UMB Backplane Firmware",
+ "Reserved", /* 0x14 */
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved", /* 0x1F */
+ "EL Chassis Abstraction Revision",
+ "EL Chassis Firmware Revision",
+ "EL Chassis PAL/CPLD",
+ "EL Cartride Abstraction Revision",
+ "Reserved", /* 0x24 */
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved", /* 0x2F */
+ "Embedded Video Controller",
+ "PCIe Riser Programmable Logic Device",
+ "PCIe cards that contain a CPLD",
+ "Intel NVMe VROC",
+ "Intel SATA VROC",
+ "Intel SPS Firmware",
+ "Secondary System Programmable Logic Device",
+ "CPU MEZZ Programmable Logic Device", /* 0x37 */
+ "Intel Artic Sound -M Accelerator Models Firmware",
+ "Ampere System Control Processor (SCP – PMPro+SMPro)",
+ "Intel CFR information", /* 0x3A */
+ };
+
+ if (code < ARRAY_SIZE(type))
+ str = type[code];
+
+ pr_attr("Firmware Type", "%s", str);
+}
+
+static void dmi_hp_216_version(u8 format, u8 *data)
+{
+ const char * const name = "Version Data";
+ const char * const reserved = "Reserved";
+ int gen;
+
+ gen = dmi_hpegen(dmi_product);
+
+ switch (format) {
+ case 0:
+ pr_attr(name, "No Version Data");
+ break;
+ case 1:
+ pr_attr(name, "%c.%d.%d", data[0] & (1 << 7) ? 'B' : 'R',
+ data[0] & 0x7, data[1] & 0x7);
+ break;
+ case 2:
+ pr_attr(name, "%d.%d", data[0] >> 4, data[0] & 0x0f);
+ break;
+ case 4:
+ pr_attr(name, "%d.%d.%d", data[0] >> 4, data[0] & 0x0f, data[1] & 0x7f);
+ break;
+ case 5:
+ if (gen == G9) {
+ pr_attr(name, "%d.%d.%d", data[0] >> 4, data[0] & 0x0f, data[1] & 0x7f);
+ } else if (gen == G10 || gen == G10P) {
+ pr_attr(name, "%d.%d.%d.%d", data[1] & 0x0f, data[3] & 0x0f,
+ data[5] & 0x0f, data[6] & 0x0f);
+ } else {
+ pr_attr(name, "%s", reserved);
+ }
+ break;
+ case 6:
+ pr_attr(name, "%d.%d", data[1], data[0]);
+ break;
+ case 7:
+ pr_attr(name, "v%d.%.2d (%.2d/%.2d/%d)", data[0], data[1],
+ data[2], data[3], WORD(data + 4));
+ break;
+ case 8:
+ pr_attr(name, "%d.%d", WORD(data + 4), WORD(data));
+ break;
+ case 9:
+ pr_attr(name, "%d.%d.%d", data[0], data[1], WORD(data + 2));
+ break;
+ case 10:
+ pr_attr(name, "%d.%d.%d Build %d", data[0], data[1], data[2], data[3]);
+ break;
+ case 11:
+ pr_attr(name, "%d.%d %d", WORD(data + 2), WORD(data), DWORD(data + 4));
+ break;
+ case 12:
+ pr_attr(name, "%d.%d.%d.%d", WORD(data), WORD(data + 2),
+ WORD(data + 4), WORD(data + 6));
+ break;
+ case 13:
+ pr_attr(name, "%d", data[0]);
+ break;
+ case 14:
+ pr_attr(name, "%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
+ break;
+ case 15:
+ pr_attr(name, "%d.%d.%d.%d (%.2d/%.2d/%d)",
+ WORD(data), WORD(data + 2), WORD(data + 4), WORD(data + 6),
+ data[8], data[9], WORD(data + 10));
+ break;
+ case 16:
+ pr_attr(name, "%c%c%c%c.%d%d",
+ data[0], data[1], data[2], data[3], data[4], data[5]);
+ break;
+ case 17:
+ pr_attr(name, "%08X", DWORD(data));
+ break;
+ case 18:
+ pr_attr(name, "%d.%2d", data[0], data[1]);
+ break;
+ case 3: /* fall through */
+ default:
+ pr_attr(name, "%s", reserved);
+ }
+}
+
+static int dmi_hp_224_status(u8 code)
+{
+ static const char * const present[] = {
+ "Not Present", /* 0x00 */
+ "Present/Enabled",
+ "Present/Disabled",
+ "Reserved" /* 0x03 */
+ };
+
+ pr_attr("Status", "%s", present[code & 0x03]);
+ if ((code & 0x03) == 0x00)
+ return 0;
+ pr_attr("Option ROM Measuring", "%s", (code & (1 << 2)) ? "Yes" : "No");
+ pr_attr("Hidden", "%s", (code & (1 << 3)) ? "Yes" : "No");
+ return 1;
+}
+
+static void dmi_hp_224_ex_status(u8 status, u8 code)
+{
+ const char *str = "Reserved";
+ static const char * const disable_reason[] = {
+ "Not Specified", /* 0x00 */
+ "User Disabled",
+ "Error Condition",
+ "Reserved" /* 0x03 */
+ };
+ static const char * const error_condition[] = {
+ "Not Specified", /* 0x00 */
+ "Self-Test", /* 0x01 */
+ };
+ if ((status & 0x03) == 0x02)
+ pr_attr("Disable Reason", "%s", disable_reason[code & 0x03]);
+ if ((code & 0x03) == 0x02) {
+ u8 error = (code >> 2) & 0x0f;
+ if (error < ARRAY_SIZE(error_condition))
+ str = error_condition[error];
+ pr_attr("Error Condition", "%s", str);
+ }
+}
+
+static void dmi_hp_224_module_type(u8 code)
+{
+ const char *str = "Reserved";
+ static const char * const type[] = {
+ "Not Specified", /* 0x00 */
+ "TPM 1.2",
+ "TPM 2.0",
+ "Intel PTT fTPM" /* 0x03 */
+ };
+ if ((code & 0x0f) < ARRAY_SIZE(type))
+ str = type[code & 0x0f];
+ pr_attr("Type", "%s", str);
+ pr_attr("Standard Algorithm Supported", "%s", (code & (1 << 4)) ? "Yes" : "No");
+ pr_attr("Chinese Algorithm Supported", "%s", (code & (1 << 5)) ? "Yes" : "No");
+}
+
+static void dmi_hp_224_module_attr(u8 code)
+{
+ static const char * const phys_attr[] = {
+ "Not Specified", /* 0x00 */
+ "Pluggable and Optional",
+ "Pluggable but Standard",
+ "Soldered Down on System Board" /* 0x03 */
+ };
+ static const char * const fips_attr[] = {
+ "Not Specified", /* 0x00 */
+ "Not FIPS Certified",
+ "FIPS Certified",
+ "Reserved" /* 0x03 */
+ };
+ pr_attr("Trusted Module Attributes", "%s", phys_attr[code & 0x3]);
+ pr_attr("FIPS Certification", "%s", fips_attr[((code >> 2) & 0x03)]);
+}
+
+static void dmi_hp_224_chipid(u16 code)
+{
+ const char *str = "Reserved";
+ static const char * const chipid[] = {
+ "None", /* 0x00 */
+ "STMicroGen10 TPM",
+ "Intel firmware TPM (PTT)",
+ "Nationz TPM",
+ "STMicroGen10 Plus TPM",
+ "STMicroGen11 TPM", /* 0x05 */
+ };
+ if ((code & 0xff) < ARRAY_SIZE(chipid))
+ str = chipid[code & 0xff];
+ pr_attr("Chip Identifier", "%s", str);
+}
+
+static void dmi_hp_230_method_bus_seg_addr(u8 code, u8 bus_seg, u8 addr)
+{
+ const char *str = "Reserved";
+ static const char * const method[] = {
+ "Not Available", /* 0x00 */
+ "IPMI I2C",
+ "iLO",
+ "Chassis Manager", /* 0x03 */
+ };
+ if (code < ARRAY_SIZE(method))
+ str = method[code];
+ pr_attr("Access Method", "%s", str);
+ if (code == 0 || code >= ARRAY_SIZE(method))
+ return;
+ if (bus_seg != 0xFF)
+ {
+ if (code == 2)
+ pr_attr("I2C Segment Number", "%d", bus_seg);
+ else
+ pr_attr("I2C Bus Number", "%d", bus_seg);
+ }
+ if (addr != 0xFF)
+ pr_attr("I2C Address", "0x%02x", addr >> 1);
+}
+
+static void dmi_hp_238_loc(const char *fname, unsigned int code)
+{
+ const char *str = "Reserved";
+ static const char *location[] = {
+ "Internal", /* 0x00 */
+ "Front of Server",
+ "Rear of Server",
+ "Embedded internal SD Card",
+ "iLO USB",
+ "USB Hub for NAND Controller",
+ "Reserved",
+ "Debug Port", /* 0x07 */
+ };
+
+ if (code < ARRAY_SIZE(location))
+ str = location[code];
+
+ pr_attr(fname, "%s", str);
+}
+
+static void dmi_hp_238_flags(const char *fname, unsigned int code)
+{
+ const char *str = "Reserved";
+ static const char *flags[] = {
+ "Not Shared", /* 0x00 */
+ "Shared with physical switch",
+ "Shared with automatic control", /* 0x02 */
+ };
+
+ if (code < ARRAY_SIZE(flags))
+ str = flags[code];
+
+ pr_attr(fname, "%s", str);
+}
+
+static void dmi_hp_238_speed(const char *fname, unsigned int code)
+{
+ const char *str = "Reserved";
+ static const char *speed[] = {
+ "Reserved", /* 0x00 */
+ "USB 1.1 Full Speed",
+ "USB 2.0 High Speed",
+ "USB 3.0 Super Speed" /* 0x03 */
+ };
+
+ if (code < ARRAY_SIZE(speed))
+ str = speed[code];
+
+ pr_attr(fname, "%s", str);
+}
+
+static void dmi_hp_242_hdd_type(u8 code)
+{
+ const char *str = "Reserved";
+ static const char * const type[] = {
+ "Undetermined", /* 0x00 */
+ "NVMe SSD",
+ "SATA",
+ "SAS",
+ "SATA SSD",
+ "NVMe Manged by VROC/VMD", /* 0x05 */
+ };
+ if (code < ARRAY_SIZE(type))
+ str = type[code];
+
+ pr_attr("Hard Drive Type", "%s", str);
+}
+
+static void dmi_hp_242_form_factor(u8 code)
+{
+ const char *str = "Reserved";
+ static const char * const form[] = {
+ "Reserved", /* 0x00 */
+ "Reserved",
+ "3.5\" form factor",
+ "2.5\" form factor",
+ "1.8\" form factor",
+ "Less than 1.8\" form factor",
+ "mSATA",
+ "M.2",
+ "MicroSSD",
+ "CFast", /* 0x09 */
+ };
+ if (code < ARRAY_SIZE(form))
+ str = form[code];
+
+ pr_attr("Form Factor", "%s", str);
+}
+
+static void dmi_hp_242_speed(const char *attr, u16 speed)
+{
+ if (speed)
+ pr_attr(attr, "%hu Gbit/s", speed);
+ else
+ pr_attr(attr, "%s", "Unknown");
+}
+
static int dmi_decode_hp(const struct dmi_header *h)
{
u8 *data = h->data;
int nic, ptr;
u32 feat;
+ const char *company = (dmi_vendor == VENDOR_HP) ? "HP" : "HPE";
+ int gen;
+
+ gen = dmi_hpegen(dmi_product);
+ if (gen < 0)
+ return 0;
switch (h->type)
{
+ case 194:
+ /*
+ * Vendor Specific: Super IO Enable/Disable Features
+ *
+ * Offset | Name | Width | Description
+ * -------------------------------------
+ * 0x00 | Type | BYTE | 0xC2, Super IO Enable/Disable Indicator
+ * 0x01 | Length | BYTE | Length of structure
+ * 0x02 | Handle | WORD | Unique handle
+ * 0x04 | Dev Status | BYTE | Device Status
+ */
+ pr_handle_name("%s ProLiant Super IO Enable/Disable Indicator", company);
+ if (h->length < 0x05) break;
+ feat = data[0x04];
+ pr_attr("Serial Port A", "%s", feat & (1 << 0) ? "Enabled" : "Disabled");
+ pr_attr("Serial Port B", "%s", feat & (1 << 1) ? "Enabled" : "Disabled");
+ pr_attr("Parallel Port", "%s", feat & (1 << 2) ? "Enabled" : "Disabled");
+ pr_attr("Floppy Disk Port", "%s", feat & (1 << 3) ? "Enabled" : "Disabled");
+ pr_attr("Virtual Serial Port", "%s", feat & (1 << 4) ? "Enabled" : "Disabled");
+ break;
+
+ case 199:
+ /*
+ * Vendor Specific: CPU Microcode Patch
+ *
+ * Offset | Name | Width | Description
+ * -------------------------------------
+ * 0x00 | Type | BYTE | 0xC7, CPU Microcode Patch
+ * 0x01 | Length | BYTE | Length of structure
+ * 0x02 | Handle | WORD | Unique handle
+ * 0x04 | Patch Info | Varies| { <DWORD: ID, DWORD Date, DWORD CPUID> ...}
+ */
+ if (gen < G9) return 0;
+ pr_handle_name("%s ProLiant CPU Microcode Patch Support Info", company);
+
+ for (ptr = 0x4; ptr + 12 <= h->length; ptr += 12) {
+ u32 cpuid = DWORD(data + ptr + 2 * 4);
+ u32 date;
+
+ /* AMD omits BaseFamily. Reconstruction valid on family >= 15. */
+ if (cpuid_type == cpuid_x86_amd)
+ cpuid = ((cpuid & 0xfff00) << 8) | 0x0f00 | (cpuid & 0xff);
+
+ dmi_print_cpuid(pr_attr, "CPU ID", cpuid_type, (u8 *) &cpuid);
+
+ date = DWORD(data + ptr + 4);
+ pr_subattr("Date", "%04x-%02x-%02x",
+ date & 0xffff, (date >> 24) & 0xff, (date >> 16) & 0xff);
+ pr_subattr("Patch", "0x%X", DWORD(data + ptr));
+ }
+ break;
+
+ case 203:
+ /*
+ * Vendor Specific: HP Device Correlation Record
+ *
+ * Offset | Name | Width | Description
+ * -------------------------------------
+ * 0x00 | Type | BYTE | 0xCB, Correlation Record
+ * 0x01 | Length | BYTE | Length of structure
+ * 0x02 | Handle | WORD | Unique handle
+ * 0x04 | Assoc Device | WORD | Handle of Associated Type 9 or Type 41 Record
+ * 0x06 | Assoc SMBus | WORD | Handle of Associated Type 228 SMBus Segment Record
+ * 0x08 | PCI Vendor ID| WORD | PCI Vendor ID of device 0xFFFF -> not present
+ * 0x0A | PCI Device ID| WORD | PCI Device ID of device 0xFFFF -> not present
+ * 0x0C | PCI SubVendor| WORD | PCI Sub Vendor ID of device 0xFFFF -> not present
+ * 0x0E | PCI SubDevice| WORD | PCI Sub Device ID of device 0xFFFF -> not present
+ * 0x10 | Class Code | BYTE | PCI Class Code of Endpoint. 0xFF if device not present.
+ * 0x11 | Class SubCode| BYTE | PCI Sub Class Code of Endpoint. 0xFF if device not present.
+ * 0x12 | Parent Handle| WORD |
+ * 0x14 | Flags | WORD |
+ * 0x16 | Device Type | BYTE | UEFI only
+ * 0x17 | Device Loc | BYTE | Device Location
+ * 0x18 | Dev Instance | BYTE | Device Instance
+ * 0x19 | Sub Instance | BYTE | NIC Port # or NVMe Drive Bay
+ * 0x1A | Bay | BYTE |
+ * 0x1B | Enclosure | BYTE |
+ * 0x1C | UEFI Dev Path| STRING| String number for UEFI Device Path
+ * 0x1D | Struct Name | STRING| String number for UEFI Device Structured Name
+ * 0x1E | Device Name | STRING| String number for UEFI Device Name
+ * 0x1F | UEFI Location| STRING| String number for UEFI Location
+ * 0x20 | Assoc Handle | WORD | Type 9 Handle. Defined if Flags[0] == 1.
+ * 0x22 | Part Number | STRING| PCI Device Part Number
+ * 0x23 | Serial Number| STRING| PCI Device Serial Number
+ * 0x24 | Seg Number | WORD | Segment Group number. 0 -> Single group topology
+ * 0x26 | Bus Number | BYTE | PCI Device Bus Number
+ * 0x27 | Func Number | BTYE | PCI Device and Function Number
+ */
+ if (gen < G9) return 0;
+ pr_handle_name("%s Device Correlation Record", company);
+ if (h->length < 0x1F) break;
+ dmi_hp_203_assoc_hndl("Associated Device Record", WORD(data + 0x04));
+ dmi_hp_203_assoc_hndl("Associated SMBus Record", WORD(data + 0x06));
+ if (WORD(data + 0x08) == 0xffff && WORD(data + 0x0A) == 0xffff &&
+ WORD(data + 0x0C) == 0xffff && WORD(data + 0x0E) == 0xffff &&
+ data[0x10] == 0xFF && data[0x11] == 0xFF)
+ {
+ pr_attr("PCI Device Info", "Device Not Present");
+ }
+ else
+ {
+ dmi_hp_203_pciinfo("PCI Vendor ID", WORD(data + 0x08));
+ dmi_hp_203_pciinfo("PCI Device ID", WORD(data + 0x0A));
+ dmi_hp_203_pciinfo("PCI Sub Vendor ID", WORD(data + 0x0C));
+ dmi_hp_203_pciinfo("PCI Sub Device ID", WORD(data + 0x0E));
+ dmi_hp_203_pciinfo("PCI Class Code", (char)data[0x10]);
+ dmi_hp_203_pciinfo("PCI Sub Class Code", (char)data[0x11]);
+ }
+ dmi_hp_203_assoc_hndl("Parent Handle", WORD(data + 0x12));
+ pr_attr("Flags", "0x%04X", WORD(data + 0x14));
+ dmi_hp_203_devtyp("Device Type", data[0x16]);
+ dmi_hp_203_devloc("Device Location", data[0x17]);
+ pr_attr("Device Instance", "%d", data[0x18]);
+ pr_attr("Device Sub-Instance", "%d", data[0x19]);
+ dmi_hp_203_bayenc("Bay", data[0x1A]);
+ dmi_hp_203_bayenc("Enclosure", data[0x1B]);
+ pr_attr("Device Path", "%s", dmi_string(h, data[0x1C]));
+ pr_attr("Structured Name", "%s", dmi_string(h, data[0x1D]));
+ pr_attr("Device Name", "%s", dmi_string(h, data[0x1E]));
+ if (h->length < 0x22) break;
+ pr_attr("UEFI Location", "%s", dmi_string(h, data[0x1F]));
+ if (!(opt.flags & FLAG_QUIET))
+ {
+ if (WORD(data + 0x14) & 1)
+ pr_attr("Associated Real/Phys Handle", "0x%04X",
+ WORD(data + 0x20));
+ else
+ pr_attr("Associated Real/Phys Handle", "N/A");
+ }
+ if (h->length < 0x24) break;
+ pr_attr("PCI Part Number", "%s", dmi_string(h, data[0x22]));
+ pr_attr("Serial Number", "%s", dmi_string(h, data[0x23]));
+ if (h->length < 0x28) break;
+ pr_attr("Segment Group Number", "0x%04x", WORD(data + 0x24));
+ pr_attr("PCI Device", "%02x:%02x.%x",
+ data[0x26], data[0x27] >> 3, data[0x27] & 7);
+ break;
+
case 204:
/*
- * Vendor Specific: HP ProLiant System/Rack Locator
+ * Vendor Specific: HPE ProLiant System/Rack Locator
*/
- printf("HP ProLiant System/Rack Locator\n");
+ pr_handle_name("%s ProLiant System/Rack Locator", company);
if (h->length < 0x0B) break;
- printf("\tRack Name: %s\n", dmi_string(h, data[0x04]));
- printf("\tEnclosure Name: %s\n", dmi_string(h, data[0x05]));
- printf("\tEnclosure Model: %s\n", dmi_string(h, data[0x06]));
- printf("\tEnclosure Serial: %s\n", dmi_string(h, data[0x0A]));
- printf("\tEnclosure Bays: %d\n", data[0x08]);
- printf("\tServer Bay: %s\n", dmi_string(h, data[0x07]));
- printf("\tBays Filled: %d\n", data[0x09]);
+ pr_attr("Rack Name", "%s", dmi_string(h, data[0x04]));
+ pr_attr("Enclosure Name", "%s", dmi_string(h, data[0x05]));
+ pr_attr("Enclosure Model", "%s", dmi_string(h, data[0x06]));
+ pr_attr("Enclosure Serial", "%s", dmi_string(h, data[0x0A]));
+ pr_attr("Enclosure Bays", "%d", data[0x08]);
+ pr_attr("Server Bay", "%s", dmi_string(h, data[0x07]));
+ pr_attr("Bays Filled", "%d", data[0x09]);
break;
case 209:
case 221:
/*
- * Vendor Specific: HP ProLiant NIC MAC Information
+ * Vendor Specific: HPE ProLiant NIC MAC Information
*
* This prints the BIOS NIC number,
* PCI bus/device/function, and MAC address
@@ -137,9 +853,9 @@ static int dmi_decode_hp(const struct dmi_header *h)
*
* Type 221: is deprecated in the latest docs
*/
- printf(h->type == 221 ?
- "HP BIOS iSCSI NIC PCI and MAC Information\n" :
- "HP BIOS PXE NIC PCI and MAC Information\n");
+ pr_handle_name("%s %s", company, h->type == 221 ?
+ "BIOS iSCSI NIC PCI and MAC Information" :
+ "BIOS PXE NIC PCI and MAC Information");
nic = 1;
ptr = 4;
while (h->length >= ptr + 8)
@@ -153,9 +869,157 @@ static int dmi_decode_hp(const struct dmi_header *h)
}
break;
+ case 212:
+ /*
+ * Vendor Specific: HPE 64-bit CRU Information
+ *
+ * Source: hpwdt kernel driver
+ */
+ pr_handle_name("%s 64-bit CRU Information", company);
+ if (h->length < 0x18) break;
+ if (is_printable(data + 0x04, 4))
+ pr_attr("Signature", "0x%08x (%c%c%c%c)",
+ DWORD(data + 0x04),
+ data[0x04], data[0x05],
+ data[0x06], data[0x07]);
+ else
+ pr_attr("Signature", "0x%08x", DWORD(data + 0x04));
+ if (DWORD(data + 0x04) == 0x55524324)
+ {
+ u64 paddr = QWORD(data + 0x08);
+ paddr.l += DWORD(data + 0x14);
+ if (paddr.l < DWORD(data + 0x14))
+ paddr.h++;
+ pr_attr("Physical Address", "0x%08x%08x",
+ paddr.h, paddr.l);
+ pr_attr("Length", "0x%08x", DWORD(data + 0x10));
+ }
+ break;
+
+ case 216:
+ /*
+ * Vendor Specific: Version Indicator Record
+ *
+ * This record is used to allow determining Firmware and CPLD revisions for
+ * components in the system. The goal of this record is to provide a
+ * flexible method to communicate to software and firmware the revisions
+ * of these components. This record replaces much of the functionality of
+ * Record Type 193. OEM SMBIOS Record Type 193 was not scaling well with
+ * the large number of potential CPLD devices, power management controllers,
+ * etc. This record is flexible such that each instance of Type 216
+ * defines one firmware component. This record also includes the string
+ * name for which software should refer to the component. The record
+ * includes both data bytes to indicate the revision and a string value. A
+ * firmware component can implement either or both. If both are supported,
+ * it allows easy display of the revision, but prevents the need for
+ * software/firmware to parse strings when doing comparisons on revisions.
+ * As there is one Type 216 Record per firmware component, the Handle for
+ * the Record can be used to tie firmware components with other OEM SMBIOS
+ * Records in the future if needed (similar to how SMBIOS Type 17 is tied
+ * to other Record Types related to DIMMs)
+ *
+ * Offset | Name | Width | Description
+ * ------------------------------------------
+ * 0x00 | Type | BYTE | 0xD8, Version Indicator Record
+ * 0x01 | Length | BYTE | Length of structure
+ * 0x02 | Handle | WORD | Unique handle
+ * 0x04 | FW Type | WORD | Type of Firmware
+ * 0x06 | FW Name | STRING | Name of Firmware
+ * 0x07 | FW Version | STRING | Firmware Version
+ * 0x08 | Data Format| BYTE | Format of the Version Data
+ * 0x09 |Version Data|12 BYTES| Version Data in Format from field 0x08
+ * 0x15 | Unique ID | WORD | Unique ID for Firmware flash
+ */
+ if (gen < G8) return 0;
+ pr_handle_name("%s Version Indicator", company);
+ if (h->length < 23) break;
+ dmi_hp_216_fw_type(WORD(data + 0x04));
+ pr_attr("Firmware Name String", "%s", dmi_string(h, data[0x06]));
+ pr_attr("Firmware Version String", "%s", dmi_string(h, data[0x07]));
+ dmi_hp_216_version(data[0x08], data + 0x09);
+ if (WORD(data + 0x15))
+ pr_attr("Unique ID", "0x%04x", WORD(data + 0x15));
+ break;
+
+ case 219:
+ /*
+ * Vendor Specific: HPE ProLiant Information
+ *
+ * Source: hpwdt kernel driver
+ */
+ pr_handle_name("%s ProLiant Information", company);
+ if (h->length < 0x08) break;
+ pr_attr("Power Features", "0x%08x", DWORD(data + 0x04));
+ if (h->length < 0x0C) break;
+ pr_attr("Omega Features", "0x%08x", DWORD(data + 0x08));
+ if (h->length < 0x14) break;
+ feat = DWORD(data + 0x10);
+ pr_attr("Misc. Features", "0x%08x", feat);
+ pr_subattr("iCRU", "%s", feat & 0x0001 ? "Yes" : "No");
+ pr_subattr("UEFI", "%s", feat & 0x1400 ? "Yes" : "No");
+ break;
+
+ case 224:
+ /*
+ * Vendor Specific: Trusted Module (TPM or TCM) Status
+ *
+ * Offset | Name | Width | Description
+ * -------------------------------------
+ * 0x00 | Type | BYTE | 0xE0, Trusted Module (TPM or TCM) Status
+ * 0x01 | Length | BYTE | Length of structure
+ * 0x02 | Handle | WORD | Unique handle
+ * 0x04 | Status | BYTE | Status Flag Byte
+ * 0x05 | Ex Stat| BYTE | TPM Extended Status
+ * 0x06 | Type | BYTE | Trusted Module Type
+ * 0x07 | Attrib | BYTE | Trusted Module Attributes
+ * 0x08 | Handle | WORD | Handle to map to Type 216
+ * 0x0A | Chip ID| WORD | Chip Identifier Values
+ */
+ pr_handle_name("%s Trusted Module (TPM or TCM) Status", company);
+ if (h->length < 0x05) break;
+ if (!dmi_hp_224_status(data[0x04]))
+ break;
+ if (h->length < 0x0a) break;
+ dmi_hp_224_ex_status(data[0x04], data[0x05]);
+ dmi_hp_224_module_type(data[0x06]);
+ dmi_hp_224_module_attr(data[0x07]);
+ if (!(opt.flags & FLAG_QUIET))
+ pr_attr("Associated Handle", "0x%04X", WORD(data + 0x8));
+ if (h->length < 0x0c) break;
+ dmi_hp_224_chipid(WORD(data + 0x0a));
+ break;
+
+ case 230:
+ /*
+ * Vendor Specific: Power Supply Information OEM SMBIOS Record
+ *
+ * This record is used to communicate additional Power Supply Information
+ * beyond the Industry Standard System Power Supply (Type 39) Record.
+ *
+ * Offset| Name | Width | Description
+ * -----------------------------------------
+ * 0x00 | Type | BYTE | 0xE6, Power Supply Information Indicator
+ * 0x01 | Length | BYTE | Length of structure
+ * 0x02 | Handle | WORD | Unique handle
+ * 0x04 | Assoc Handle| WORD | Associated Handle (Type 39)
+ * 0x06 | Manufacturer| STRING| Actual third party manufacturer
+ * 0x07 | Revision | STRING| Power Supply Revision Level
+ * 0x08 | FRU Access | BYTE | Power Supply FRU Access Method
+ * 0x09 | I2C Bus Num | BYTE | I2C Bus #. Value based upon context
+ * 0x0A | I2C Address | BYTE | I2C Address
+ */
+ pr_handle_name("%s Power Supply Information", company);
+ if (h->length < 0x0B) break;
+ if (!(opt.flags & FLAG_QUIET))
+ pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4));
+ pr_attr("Manufacturer", "%s", dmi_string(h, data[0x06]));
+ pr_attr("Revision", "%s", dmi_string(h, data[0x07]));
+ dmi_hp_230_method_bus_seg_addr(data[0x08], data[0x09], data[0x0A]);
+ break;
+
case 233:
/*
- * Vendor Specific: HP ProLiant NIC MAC Information
+ * Vendor Specific: HPE ProLiant NIC MAC Information
*
* This prints the BIOS NIC number,
* PCI bus/device/function, and MAC address
@@ -171,7 +1035,8 @@ static int dmi_decode_hp(const struct dmi_header *h)
* 0x08 | MAC | 32B | MAC addr padded w/ 0s
* 0x28 | Port No| BYTE | Each NIC maps to a Port
*/
- printf("HP BIOS PXE NIC PCI and MAC Information\n");
+ pr_handle_name("%s BIOS PXE NIC PCI and MAC Information",
+ company);
if (h->length < 0x0E) break;
/* If the record isn't long enough, we don't have an ID
* use 0xFF to use the internal counter.
@@ -181,89 +1046,340 @@ static int dmi_decode_hp(const struct dmi_header *h)
&data[0x08]);
break;
- case 212:
+ case 236:
/*
- * Vendor Specific: HP 64-bit CRU Information
+ * Vendor Specific: HPE ProLiant HDD Backplane
*
- * Source: hpwdt kernel driver
+ * Offset | Name | Width | Description
+ * ---------------------------------------
+ * 0x00 | Type | BYTE | 0xEC, HDD Backplane
+ * 0x01 | Length | BYTE | Length of structure
+ * 0x02 | Handle | WORD | Unique handle
+ * 0x04 | I2C Address| BYTE | Backplane FRU I2C Address
+ * 0x05 | Box Number | WORD | Backplane Box Number
+ * 0x07 | NVRAM ID | WORD | Backplane NVRAM ID
+ * 0x09 | WWID | QWORD | SAS Expander WWID
+ * 0x11 | Total Bays | BYTE | Total SAS Bays
+ * 0x12 | A0 Bays | BYTE | (deprecated) Number of SAS drive bays behind port 0xA0
+ * 0x13 | A2 Bays | BYTE | (deprecated) Number of SAS drive bays behind port 0xA2
+ * 0x14 | Name | STRING| (deprecated) Backplane Name
*/
- printf("HP 64-bit CRU Information\n");
- if (h->length < 0x18) break;
- printf("\tSignature: 0x%08x", DWORD(data + 0x04));
- if (is_printable(data + 0x04, 4))
- printf(" (%c%c%c%c)", data[0x04], data[0x05],
- data[0x06], data[0x07]);
- printf("\n");
- if (DWORD(data + 0x04) == 0x55524324)
- {
- u64 paddr = QWORD(data + 0x08);
- paddr.l += DWORD(data + 0x14);
- if (paddr.l < DWORD(data + 0x14))
- paddr.h++;
- printf("\tPhysical Address: 0x%08x%08x\n",
- paddr.h, paddr.l);
- printf("\tLength: 0x%08x\n", DWORD(data + 0x10));
+ pr_handle_name("%s HDD Backplane FRU Information", company);
+ if (h->length < 0x08) break;
+ pr_attr("FRU I2C Address", "0x%X raw(0x%X)", data[0x4] >> 1, data[0x4]);
+ pr_attr("Box Number", "%d", WORD(data + 0x5));
+ pr_attr("NVRAM ID", "0x%X", WORD(data + 0x7));
+ if (h->length < 0x11) break;
+ pr_attr("SAS Expander WWID", "0x%X", QWORD(data + 0x9));
+ if (h->length < 0x12) break;
+ pr_attr("Total SAS Bays", "%d", data[0x11]);
+ if (h->length < 0x15) break;
+ if (gen < G10P) {
+ pr_attr("A0 Bay Count", "%d", data[0x12]);
+ pr_attr("A2 Bay Count", "%d", data[0x13]);
+ pr_attr("Backplane Name", "%s", dmi_string(h, data[0x14]));
}
break;
- case 219:
+ case 237:
/*
- * Vendor Specific: HP ProLiant Information
+ * Vendor Specific: HPE DIMM Vendor Part Number Information
*
- * Source: hpwdt kernel driver
+ * Offset | Name | Width | Description
+ * ---------------------------------------
+ * 0x00 | Type | BYTE | 0xED, DIMM Vendor Part Number information record
+ * 0x01 | Length | BYTE | Length of structure
+ * 0x02 | Handle | WORD | Unique handle
+ * 0x04 | Hand Assoc | WORD | Handle to map to Type 17
+ * 0x06 | Manufacture|STRING | DIMM Manufacturer
+ * 0x07 | Part Number|STRING | DIMM Manufacturer's Part Number
+ * 0x08 | Serial Num |STRING | DIMM Vendor Serial Number
+ * 0x09 | Spare Part |STRING | DIMM Spare Part Number
*/
- printf("HP ProLiant Information\n");
+ if (gen < G9) return 0;
+ pr_handle_name("%s DIMM Vendor Information", company);
if (h->length < 0x08) break;
- printf("\tPower Features: 0x%08x\n", DWORD(data + 0x04));
- if (h->length < 0x0C) break;
- printf("\tOmega Features: 0x%08x\n", DWORD(data + 0x08));
- if (h->length < 0x14) break;
- feat = DWORD(data + 0x10);
- printf("\tMisc. Features: 0x%08x\n", feat);
- printf("\t\tiCRU: %s\n", feat & 0x0001 ? "Yes" : "No");
- printf("\t\tUEFI: %s\n", feat & 0x0408 ? "Yes" : "No");
+ if (!(opt.flags & FLAG_QUIET))
+ pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4));
+ pr_attr("DIMM Manufacturer", "%s", dmi_string(h, data[0x06]));
+ pr_attr("DIMM Manufacturer Part Number", "%s", dmi_string(h, data[0x07]));
+ if (h->length < 0x09) break;
+ pr_attr("DIMM Vendor Serial Number", "%s", dmi_string(h, data[0x08]));
+ if (h->length < 0x0A) break;
+ pr_attr("DIMM Spare Part Number", "%s", dmi_string(h, data[0x09]));
break;
+ case 238:
+ /*
+ * Vendor Specific: HPE USB Port Connector Correlation Record
+ *
+ * Offset | Name | Width | Description
+ * ---------------------------------------
+ * 0x00 | Type | BYTE | 0xEE, HP Device Correlation Record
+ * 0x01 | Length | BYTE | Length of structure
+ * 0x02 | Handle | WORD | Unique handle
+ * 0x04 | Hand Assoc | WORD | Handle to map to Type 8
+ * 0x06 | Parent Bus | BYTE | PCI Bus number of USB controller of this port
+ * 0x07 | Par Dev/Fun| BYTE | PCI Dev/Fun of USB Controller of this port
+ * 0x08 | Location | BYTE | Enumerated value of location of USB port
+ * 0x09 | Flags | WORD | USB Shared Management Port
+ * 0x0B | Port Inst | BYTE | Instance number for this type of USB port
+ * 0x0C | Parent Hub | BYTE | Instance number of internal Hub
+ * 0x0D | Port Speed | BYTE | Enumerated value of speed configured by BIOS
+ * 0x0E | Device Path| STRING| UEFI Device Path of USB endpoint
+ */
+ if (gen < G9) return 0;
+ pr_handle_name("%s Proliant USB Port Connector Correlation Record", company);
+ if (h->length < 0x0F) break;
+ if (!(opt.flags & FLAG_QUIET))
+ pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4));
+ pr_attr("PCI Device", "%02x:%02x.%x", data[0x6],
+ data[0x7] >> 3, data[0x7] & 0x7);
+ dmi_hp_238_loc("Location", data[0x8]);
+ dmi_hp_238_flags("Management Port", WORD(data + 0x9));
+ pr_attr("Port Instance", "%d", data[0xB]);
+ if (data[0xC] != 0xFE)
+ pr_attr("Parent Hub Port Instance", "%d", data[0xC]);
+ else
+ pr_attr("Parent Hub Port Instance", "N/A");
+ dmi_hp_238_speed("Port Speed Capability", data[0xD]);
+ pr_attr("Device Path", "%s", dmi_string(h, data[0xE]));
+ break;
+
+ case 240:
+ /*
+ * Vendor Specific: HPE Proliant Inventory Record
+ *
+ * Reports firmware version information for devices that report their
+ * firmware using their UEFI drivers. Additionally provides association
+ * with other SMBIOS records, such as Type 203 (which in turn is
+ * associated with Types 9, 41, and 228).
+ *
+ * Offset | Name | Width | Description
+ * ---------------------------------------
+ * 0x00 | Type | BYTE | 0xF0, HP Firmware Inventory Record
+ * 0x01 | Length | BYTE | Length of structure
+ * 0x02 | Handle | WORD | Unique handle
+ * 0x04 | Hndl Assoc | WORD | Handle to map to Type 203
+ * 0x06 | Pkg Vers | DWORD | FW Vers Release of All FW in Device
+ * 0x0A | Ver String | STRING| FW Version String
+ * 0x0B | Image Size | QWORD | FW image size (bytes)
+ * 0x13 | Attributes | QWORD | Bitfield: Is attribute defined?
+ * 0x1B | Attr Set | QWORD | BitField: If defined, is attribute set?
+ * 0x23 | Version | DWORD | Lowest supported version.
+ */
+ pr_handle_name("%s Proliant Inventory Record", company);
+ if (h->length < 0x27) break;
+ if (!(opt.flags & FLAG_QUIET))
+ pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4));
+ pr_attr("Package Version", "0x%08X", DWORD(data + 0x6));
+ pr_attr("Version String", "%s", dmi_string(h, data[0x0A]));
+
+ if (DWORD(data + 0x0B))
+ dmi_print_memory_size("Image Size", QWORD(data + 0xB), 0);
+ else
+ pr_attr("Image Size", "Not Available");
+
+ dmi_hp_240_attr(QWORD(data + 0x13), QWORD(data + 0x1B));
+
+ if (DWORD(data + 0x23))
+ pr_attr("Lowest Supported Version", "0x%08X", DWORD(data + 0x23));
+ else
+ pr_attr("Lowest Supported Version", "Not Available");
+ break;
+
+ case 242:
+ /*
+ * Vendor Specific: HPE Hard Drive Inventory Record
+ *
+ * This record provides a mechanism for software to gather information for
+ * NVMe and SATA drives that are directly attached to the system. This
+ * record does not contain drive information for drives attached to a HBA
+ * (i.e. a SmartArray controller). This record will only contain information
+ * for a hard drive detected by the BIOS during POST and does not
+ * comprehend a hot plug event after the system has booted.
+ *
+ * Offset | Name | Width | Description
+ * ---------------------------------------
+ * 0x00 | Type | BYTE | 0xF2, HPE Hard Drive Inventory Record
+ * 0x01 | Length | BYTE | Length of structure
+ * 0x02 | Handle | WORD | Unique handle
+ * 0x04 | Hndl Assoc | WORD | Handle to map to Type 203
+ * 0x06 | HDD Type | BYTE | Hard drive type
+ * 0x07 | HDD Uniq ID| QWORD | SATA-> WWID. NVMe -> IEEE Ext Uniq ID.
+ * 0x0F | Capacity | DWORD | Drive Capacity in Mbytes
+ * 0x13 | Hours | 16BYTE| Number of poweron hours
+ * 0x23 | Reserved | BYTE | Reserved
+ * 0x24 | Power | BTYE | Wattage
+ * 0x25 | Form Factor| BYTE | HDD Form Factor
+ * 0x26 | Health | BYTE | Hard Drive Health Status
+ * 0x27 | Serial Num | STRING| NVMe/SATA Serial Number
+ * 0x28 | Model Num | STRING| NVMe/SATA Model Number
+ * 0x29 | FW Rev | STRING| Firmware revision
+ * 0x2A | Location | STRING| Drive location
+ * 0x2B | Crypt Stat | BYTE | Drive encryption status from BIOS
+ * 0x2C | Capacity | QWORD | Hard Drive capacity in bytes
+ * 0x34 | Block Size | DWORD | Logical Block Size in bytes
+ * 0x38 | Rot Speed | WORD | Nominal Rotational Speed (RPM)
+ * 0x3A | Neg Speed | WORD | Current negotiated bus speed
+ * 0x3C | Cap Speed | WORD | Fastest Capable Bus Speed of drive
+ */
+ if (gen < G10) return 0;
+ pr_handle_name("%s ProLiant Hard Drive Inventory Record", company);
+ if (h->length < 0x2C) break;
+ if (!(opt.flags & FLAG_QUIET))
+ pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4));
+ dmi_hp_242_hdd_type(data[0x06]);
+ pr_attr("ID", "%llx", QWORD(data + 0x07));
+ if (h->length < 0x3E)
+ pr_attr("Capacity", "%u MB", DWORD(data + 0x0F));
+ else
+ dmi_print_memory_size("Capacity", QWORD(data + 0x2C), 0);
+ /* NB: Poweron low QWORD good for 2,104,351,365,926,255 years */
+ pr_attr("Poweron", "%ld hours", QWORD(data + 0x13));
+ if (data[0x24])
+ pr_attr("Power Wattage", "%hhu W", data[0x24]);
+ else
+ pr_attr("Power Wattage", "%s", "Unknown");
+ dmi_hp_242_form_factor(data[0x25]);
+ feat = data[0x26];
+ pr_attr("Health Status", "%s", (feat == 0x00) ? "OK" :
+ (feat == 0x01) ? "Warning" :
+ (feat == 0x02) ? "Critical" :
+ (feat == 0xFF) ? "Unknown" : "Reserved");
+ pr_attr("Serial Number", dmi_string(h, data[0x27]));
+ pr_attr("Model Number", dmi_string(h, data[0x28]));
+ pr_attr("Firmware Revision", dmi_string(h, data[0x29]));
+ pr_attr("Location", dmi_string(h, data[0x2A]));
+ feat = data[0x2B];
+ pr_attr("Encryption Status", "%s", (feat == 0) ? "Not Encrypted" :
+ (feat == 1) ? "Encrypted" :
+ (feat == 2) ? "Unknown" :
+ (feat == 3) ? "Not Supported" : "Reserved");
+ if (h->length < 0x3E) break;
+ pr_attr("Block Size", "%u bytes", DWORD(data + 0x34));
+ /* Rotational Speed: 0 -> Not Reported, 1 -> N/A (SSD) */
+ if (data[0x38] > 1)
+ pr_attr("Rotational Speed", "%hhu RPM", data[0x38]);
+ dmi_hp_242_speed("Negotiated Speed", WORD(data + 0x3A));
+ dmi_hp_242_speed("Capable Speed", WORD(data + 0x3C));
+ break;
default:
return 0;
}
return 1;
}
-/*
- * Acer-specific data structures are decoded here.
- */
-
-static int dmi_decode_acer(const struct dmi_header *h)
+static int dmi_decode_ibm_lenovo(const struct dmi_header *h)
{
u8 *data = h->data;
- u16 cap;
switch (h->type)
{
- case 170:
+ case 131:
/*
- * Vendor Specific: Acer Hotkey Function
+ * Vendor Specific: ThinkVantage Technologies feature bits
*
- * Source: acer-wmi kernel driver
+ * Source: Compal hel81 Service Manual Software Specification,
+ * documented under "System Management BIOS(SM BIOS)
+ * version 2.4 or greater"
*
- * Probably applies to some laptop models of other
- * brands, including Fujitsu-Siemens, Medion, Lenovo,
- * and eMachines.
+ * Offset | Name | Width | Description
+ * ----------------------------------------------
+ * 0x00 | Type | BYTE | 0x83
+ * 0x01 | Length | BYTE | 0x16
+ * 0x02 | Handle | WORD | Varies
+ * 0x04 | Version | BYTE | 0x01
+ * 0x05 | TVT Structure | BYTEx16 | Each of the 128 bits represents a TVT feature:
+ * | | | - bit 127 means diagnostics (PC Doctor) is available
+ * | | | (http://www.pc-doctor.com/company/pr-articles/45-lenovo-introduces-thinkvantage-toolbox)
+ * | | | - the rest (126-0) are reserved/unknown
+ *
+ * It must also be followed by a string containing
+ * "TVT-Enablement". There exist other type 131 records
+ * with different length and a different string, for
+ * other purposes.
*/
- printf("Acer Hotkey Function\n");
- if (h->length < 0x0F) break;
- cap = WORD(data + 0x04);
- printf("\tFunction bitmap for Communication Button: 0x%04hx\n", cap);
- printf("\t\tWiFi: %s\n", cap & 0x0001 ? "Yes" : "No");
- printf("\t\t3G: %s\n", cap & 0x0040 ? "Yes" : "No");
- printf("\t\tWiMAX: %s\n", cap & 0x0080 ? "Yes" : "No");
- printf("\t\tBluetooth: %s\n", cap & 0x0800 ? "Yes" : "No");
- printf("\tFunction bitmap for Application Button: 0x%04hx\n", WORD(data + 0x06));
- printf("\tFunction bitmap for Media Button: 0x%04hx\n", WORD(data + 0x08));
- printf("\tFunction bitmap for Display Button: 0x%04hx\n", WORD(data + 0x0A));
- printf("\tFunction bitmap for Others Button: 0x%04hx\n", WORD(data + 0x0C));
- printf("\tCommunication Function Key Number: %d\n", data[0x0E]);
+
+ if (h->length != 0x16
+ || strcmp(dmi_string(h, 1), "TVT-Enablement") != 0)
+ return 0;
+
+ pr_handle_name("ThinkVantage Technologies");
+ pr_attr("Version", "%u", data[0x04]);
+ pr_attr("Diagnostics", "%s",
+ data[0x14] & 0x80 ? "Available" : "No");
+ break;
+
+ case 135:
+ /*
+ * Vendor Specific: Device Presence Detection bits
+ *
+ * Source: Compal hel81 Service Manual Software Specification,
+ * documented as "SMBIOS Type 135: Bulk for Lenovo
+ * Mobile PC Unique OEM Data" under appendix D.
+ *
+ * Offset | Name | Width | Description
+ * ---------------------------------------------------
+ * 0x00 | Type | BYTE | 0x87
+ * 0x01 | Length | BYTE | 0x0A
+ * 0x02 | Handle | WORD | Varies
+ * 0x04 | Signature | WORD | 0x5054 (ASCII for "TP")
+ * 0x06 | OEM struct offset | BYTE | 0x07
+ * 0x07 | OEM struct number | BYTE | 0x03, for this structure
+ * 0x08 | OEM struct revision | BYTE | 0x01, for this format
+ * 0x09 | Device presence bits | BYTE | Each of the 8 bits indicates device presence:
+ * | | | - bit 0 indicates the presence of a fingerprint reader
+ * | | | - the rest (7-1) are reserved/unknown
+ *
+ * Other OEM struct number+rev combinations have been
+ * seen in the wild but we don't know how to decode
+ * them.
+ */
+
+ if (h->length < 0x0A || data[0x04] != 'T' || data[0x05] != 'P')
+ return 0;
+
+ /* Bail out if not the expected format */
+ if (data[0x06] != 0x07 || data[0x07] != 0x03 || data[0x08] != 0x01)
+ return 0;
+
+ pr_handle_name("ThinkPad Device Presence Detection");
+ pr_attr("Fingerprint Reader", "%s",
+ data[0x09] & 0x01 ? "Present" : "No");
+ break;
+
+ case 140:
+ /*
+ * Vendor Specific: ThinkPad Embedded Controller Program
+ *
+ * Source: some guesswork, and publicly available information;
+ * Lenovo's BIOS update READMEs often contain the ECP IDs
+ * which match the first string in this type.
+ *
+ * Offset | Name | Width | Description
+ * ----------------------------------------------------
+ * 0x00 | Type | BYTE | 0x8C
+ * 0x01 | Length | BYTE |
+ * 0x02 | Handle | WORD | Varies
+ * 0x04 | Signature | BYTEx6 | ASCII for "LENOVO"
+ * 0x0A | OEM struct offset | BYTE | 0x0B
+ * 0x0B | OEM struct number | BYTE | 0x07, for this structure
+ * 0x0C | OEM struct revision | BYTE | 0x01, for this format
+ * 0x0D | ECP version ID | STRING |
+ * 0x0E | ECP release date | STRING |
+ */
+
+ if (h->length < 0x0F || memcmp(data + 4, "LENOVO", 6) != 0)
+ return 0;
+
+ /* Bail out if not the expected format */
+ if (data[0x0A] != 0x0B || data[0x0B] != 0x07 || data[0x0C] != 0x01)
+ return 0;
+
+ pr_handle_name("ThinkPad Embedded Controller Program");
+ pr_attr("Version ID", "%s", dmi_string(h, 1));
+ pr_attr("Release Date", "%s", dmi_string(h, 2));
break;
default:
@@ -281,9 +1397,13 @@ int dmi_decode_oem(const struct dmi_header *h)
switch (dmi_vendor)
{
case VENDOR_HP:
+ case VENDOR_HPE:
return dmi_decode_hp(h);
case VENDOR_ACER:
return dmi_decode_acer(h);
+ case VENDOR_IBM:
+ case VENDOR_LENOVO:
+ return dmi_decode_ibm_lenovo(h);
default:
return 0;
}
diff --git a/dmioem.h b/dmioem.h
index 3916766..b79b769 100644
--- a/dmioem.h
+++ b/dmioem.h
@@ -21,5 +21,5 @@
struct dmi_header;
-void dmi_set_vendor(const char *s);
+void dmi_set_vendor(const char *s, const char *p);
int dmi_decode_oem(const struct dmi_header *h);
diff --git a/dmiopt.c b/dmiopt.c
index da42546..fa84f22 100644
--- a/dmiopt.c
+++ b/dmiopt.c
@@ -113,7 +113,7 @@ static u8 *parse_opt_type(u8 *p, const char *arg)
char *next;
val = strtoul(arg, &next, 0);
- if (next == arg)
+ if (next == arg || (*next != '\0' && *next != ',' && *next != ' '))
{
fprintf(stderr, "Invalid type keyword: %s\n", arg);
print_opt_type_list();
@@ -151,11 +151,15 @@ static const struct string_keyword opt_string_keyword[] = {
{ "bios-vendor", 0, 0x04 },
{ "bios-version", 0, 0x05 },
{ "bios-release-date", 0, 0x08 },
+ { "bios-revision", 0, 0x15 }, /* 0x14 and 0x15 */
+ { "firmware-revision", 0, 0x17 }, /* 0x16 and 0x17 */
{ "system-manufacturer", 1, 0x04 },
{ "system-product-name", 1, 0x05 },
{ "system-version", 1, 0x06 },
{ "system-serial-number", 1, 0x07 },
{ "system-uuid", 1, 0x08 }, /* dmi_system_uuid() */
+ { "system-sku-number", 1, 0x19 },
+ { "system-family", 1, 0x1a },
{ "baseboard-manufacturer", 2, 0x04 },
{ "baseboard-product-name", 2, 0x05 },
{ "baseboard-version", 2, 0x06 },
@@ -227,7 +231,7 @@ static int parse_opt_oem_string(const char *arg)
goto done;
val = strtoul(arg, &next, 10);
- if (next == arg || val == 0x00 || val > 0xff)
+ if (next == arg || *next != '\0' || val == 0x00 || val > 0xff)
{
fprintf(stderr, "Invalid OEM string number: %s\n", arg);
return -1;
@@ -239,6 +243,19 @@ done:
return 0;
}
+static u32 parse_opt_handle(const char *arg)
+{
+ u32 val;
+ char *next;
+
+ val = strtoul(arg, &next, 0);
+ if (next == arg || *next != '\0' || val > 0xffff)
+ {
+ fprintf(stderr, "Invalid handle number: %s\n", arg);
+ return ~0;
+ }
+ return val;
+}
/*
* Command line options handling
@@ -248,16 +265,18 @@ done:
int parse_command_line(int argc, char * const argv[])
{
int option;
- const char *optstring = "d:hqs:t:uV";
+ const char *optstring = "d:hqs:t:uH:V";
struct option longopts[] = {
{ "dev-mem", required_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "quiet", no_argument, NULL, 'q' },
+ { "no-quirks", no_argument, NULL, 'Q' },
{ "string", required_argument, NULL, 's' },
{ "type", required_argument, NULL, 't' },
{ "dump", no_argument, NULL, 'u' },
{ "dump-bin", required_argument, NULL, 'B' },
{ "from-dump", required_argument, NULL, 'F' },
+ { "handle", required_argument, NULL, 'H' },
{ "oem-string", required_argument, NULL, 'O' },
{ "no-sysfs", no_argument, NULL, 'S' },
{ "version", no_argument, NULL, 'V' },
@@ -284,6 +303,9 @@ int parse_command_line(int argc, char * const argv[])
case 'q':
opt.flags |= FLAG_QUIET;
break;
+ case 'Q':
+ opt.flags |= FLAG_NO_QUIRKS;
+ break;
case 's':
if (parse_opt_string(optarg) < 0)
return -1;
@@ -299,6 +321,11 @@ int parse_command_line(int argc, char * const argv[])
if (opt.type == NULL)
return -1;
break;
+ case 'H':
+ opt.handle = parse_opt_handle(optarg);
+ if (opt.handle == ~0U)
+ return -1;
+ break;
case 'u':
opt.flags |= FLAG_DUMP;
break;
@@ -325,9 +352,9 @@ int parse_command_line(int argc, char * const argv[])
/* Check for mutually exclusive output format options */
if ((opt.string != NULL) + (opt.type != NULL)
- + !!(opt.flags & FLAG_DUMP_BIN) > 1)
+ + !!(opt.flags & FLAG_DUMP_BIN) + (opt.handle != ~0U) > 1)
{
- fprintf(stderr, "Options --string, --type and --dump-bin are mutually exclusive\n");
+ fprintf(stderr, "Options --string, --type, --handle and --dump-bin are mutually exclusive\n");
return -1;
}
@@ -348,8 +375,10 @@ void print_help(void)
" -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n"
" -h, --help Display this help text and exit\n"
" -q, --quiet Less verbose output\n"
+ " --no-quirks Decode everything without quirks\n"
" -s, --string KEYWORD Only display the value of the given DMI string\n"
" -t, --type TYPE Only display the entries of given type\n"
+ " -H, --handle HANDLE Only display the entry of given handle\n"
" -u, --dump Do not decode the entries\n"
" --dump-bin FILE Dump the DMI data to a binary file\n"
" --from-dump FILE Read the DMI data from a binary file\n"
diff --git a/dmiopt.h b/dmiopt.h
index c676308..62ffcbb 100644
--- a/dmiopt.h
+++ b/dmiopt.h
@@ -35,6 +35,7 @@ struct opt
u8 *type;
const struct string_keyword *string;
char *dumpfile;
+ u32 handle;
};
extern struct opt opt;
@@ -45,6 +46,7 @@ extern struct opt opt;
#define FLAG_DUMP_BIN (1 << 4)
#define FLAG_FROM_DUMP (1 << 5)
#define FLAG_NO_SYSFS (1 << 6)
+#define FLAG_NO_QUIRKS (1 << 7)
int parse_command_line(int argc, char * const argv[]);
void print_help(void);
diff --git a/dmioutput.c b/dmioutput.c
new file mode 100644
index 0000000..42f8d32
--- /dev/null
+++ b/dmioutput.c
@@ -0,0 +1,137 @@
+/*
+ * Generic output functions
+ * This file is part of the dmidecode project.
+ *
+ * Copyright (C) 2020 Jean Delvare <jdelvare@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "dmioutput.h"
+
+void pr_comment(const char *format, ...)
+{
+ va_list args;
+
+ printf("# ");
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ printf("\n");
+}
+
+void pr_info(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ printf("\n");
+}
+
+void pr_handle(const struct dmi_header *h)
+{
+ printf("Handle 0x%04X, DMI type %d, %d bytes\n",
+ h->handle, h->type, h->length);
+}
+
+void pr_handle_name(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ printf("\n");
+}
+
+void pr_attr(const char *name, const char *format, ...)
+{
+ va_list args;
+
+ printf("\t%s: ", name);
+
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ printf("\n");
+}
+
+void pr_subattr(const char *name, const char *format, ...)
+{
+ va_list args;
+
+ printf("\t\t%s: ", name);
+
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ printf("\n");
+}
+
+void pr_list_start(const char *name, const char *format, ...)
+{
+ va_list args;
+
+ printf("\t%s:", name);
+
+ /* format is optional, skip value if not provided */
+ if (format)
+ {
+ printf(" ");
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ }
+ printf("\n");
+
+}
+
+void pr_list_item(const char *format, ...)
+{
+ va_list args;
+
+ printf("\t\t");
+
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ printf("\n");
+}
+
+void pr_list_end(void)
+{
+ /* a no-op for text output */
+}
+
+void pr_sep(void)
+{
+ printf("\n");
+}
+
+void pr_struct_err(const char *format, ...)
+{
+ va_list args;
+
+ printf("\t");
+
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ printf("\n");
+}
diff --git a/dmioutput.h b/dmioutput.h
new file mode 100644
index 0000000..a492ec0
--- /dev/null
+++ b/dmioutput.h
@@ -0,0 +1,34 @@
+/*
+ * Generic output functions
+ * This file is part of the dmidecode project.
+ *
+ * Copyright (C) 2020 Jean Delvare <jdelvare@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "dmidecode.h"
+
+void pr_comment(const char *format, ...);
+void pr_info(const char *format, ...);
+void pr_handle(const struct dmi_header *h);
+void pr_handle_name(const char *format, ...);
+void pr_attr(const char *name, const char *format, ...);
+void pr_subattr(const char *name, const char *format, ...);
+void pr_list_start(const char *name, const char *format, ...);
+void pr_list_item(const char *format, ...);
+void pr_list_end(void);
+void pr_sep(void);
+void pr_struct_err(const char *format, ...);
diff --git a/man/biosdecode.8 b/man/biosdecode.8
index c39d6a0..b0996d7 100644
--- a/man/biosdecode.8
+++ b/man/biosdecode.8
@@ -1,10 +1,12 @@
.TH BIOSDECODE 8 "February 2007" "dmidecode"
+.\"
.SH NAME
biosdecode \- \s-1BIOS\s0 information decoder
+.\"
.SH SYNOPSIS
.B biosdecode
-.RB [ OPTIONS ]
-
+.RI [ OPTIONS ]
+.\"
.SH DESCRIPTION
.B biosdecode
parses the \s-1BIOS\s0 memory and prints information about all structures (or
@@ -54,28 +56,35 @@ started its life as a part of
.B dmidecode
but as more entry point types were added, it was moved to a different
program.
-
+.\"
.SH OPTIONS
.TP
-.BR "-d" ", " "--dev-mem FILE"
-Read memory from device \fBFILE\fR (default: \fB/dev/mem\fR)
+.BR "-d" ", " "--dev-mem \fIFILE\fP"
+Read memory from device \fIFILE\fP (default: \fI/dev/mem\fP)
+.TP
+.BR " " " " "--pir \fBfull\fP"
+Decode the details of the PCI IRQ routing table.
+Only \fBfull\fP mode is supported.
.TP
.BR "-h" ", " "--help"
Display usage information and exit
.TP
.BR "-V" ", " "--version"
Display the version and exit
-
+.\"
.SH FILES
.I /dev/mem
+.\"
.SH BUGS
Most of the time,
.B biosdecode
prints too much information (you don't really care about addresses)
or not enough (because it doesn't follow pointers and has no lookup
tables).
+.\"
.SH AUTHORS
Alan Cox, Jean Delvare
+.\"
.SH "SEE ALSO"
.BR dmidecode (8),
.BR mem (4),
diff --git a/man/dmidecode.8 b/man/dmidecode.8
index bef204e..83affc2 100644
--- a/man/dmidecode.8
+++ b/man/dmidecode.8
@@ -1,10 +1,12 @@
-.TH DMIDECODE 8 "March 2012" "dmidecode"
+.TH DMIDECODE 8 "February 2023" "dmidecode"
+.\"
.SH NAME
dmidecode \- \s-1DMI\s0 table decoder
+.\"
.SH SYNOPSIS
.B dmidecode
-.RB [ OPTIONS ]
-
+.RI [ OPTIONS ]
+.\"
.SH DESCRIPTION
.B dmidecode
is a tool for dumping a computer's \s-1DMI\s0 (some say \s-1SMBIOS\s0) table
@@ -58,37 +60,61 @@ displayed value.
Decoded values. The information presented of course depends on the type
of record. Here, we learn about the board's manufacturer, model, version
and serial number.
-
+.\"
.SH OPTIONS
.TP
-.BR "-d" ", " "--dev-mem FILE"
-Read memory from device \fBFILE\fR (default: \fB/dev/mem\fR)
+.BR "-d" ", " "--dev-mem \fIFILE\fP"
+Read memory from device \fIFILE\fP (default: \fI/dev/mem\fP)
.TP
.BR "-q" ", " "--quiet"
Be less verbose. Unknown, inactive and \s-1OEM\s0-specific entries are not
displayed. Meta-data and handle references are hidden.
.TP
-.BR "-s" ", " "--string KEYWORD"
-Only display the value of the \s-1DMI\s0 string identified by \fBKEYWORD\fR.
-\fBKEYWORD\fR must be a keyword from the following list: \fBbios-vendor\fR,
-\fBbios-version\fR, \fBbios-release-date\fR,
-\fBsystem-manufacturer\fR, \fBsystem-product-name\fR,
-\fBsystem-version\fR, \fBsystem-serial-number\fR,
-\fBsystem-uuid\fR,
-\fBbaseboard-manufacturer\fR, \fBbaseboard-product-name\fR,
-\fBbaseboard-version\fR, \fBbaseboard-serial-number\fR,
-\fBbaseboard-asset-tag\fR, \fBchassis-manufacturer\fR,
-\fBchassis-type\fR,
-\fBchassis-version\fR, \fBchassis-serial-number\fR,
-\fBchassis-asset-tag\fR, \fBprocessor-family\fR,
-\fBprocessor-manufacturer\fR,
-\fBprocessor-version\fR, \fBprocessor-frequency\fR.
+.BR " " " " "--no-quirks"
+Decode everything exactly as it is in the table, without trying to fix up
+common mistakes or hide irrelevant fields.
+This mode is primarily aimed at firmware developers.
+.TP
+.BR "-s" ", " "--string \fIKEYWORD\fP"
+Only display the value of the \s-1DMI\s0 string identified by \fIKEYWORD\fP.
+It must be a keyword from the following list:
+.nh
+.BR bios\-vendor ,
+.BR bios\-version ,
+.BR bios\-release\-date ,
+.BR bios\-revision ,
+.BR firmware\-revision ,
+.BR system\-manufacturer ,
+.BR system\-product\-name ,
+.BR system\-version ,
+.BR system\-serial\-number ,
+.BR system\-uuid ,
+.BR system\-sku\-number ,
+.BR system\-family ,
+.BR baseboard\-manufacturer ,
+.BR baseboard\-product\-name ,
+.BR baseboard\-version ,
+.BR baseboard\-serial\-number ,
+.BR baseboard\-asset\-tag ,
+.BR chassis\-manufacturer ,
+.BR chassis\-type ,
+.BR chassis\-version ,
+.BR chassis\-serial\-number ,
+.BR chassis\-asset\-tag ,
+.BR processor\-family ,
+.BR processor\-manufacturer ,
+.BR processor\-version ,
+.BR processor\-frequency .
+.hy
Each keyword corresponds to a given \s-1DMI\s0 type and a given offset
within this entry type.
Not all strings may be meaningful or even defined on all systems. Some
keywords may return more than one result on some systems (e.g.
-\fBprocessor-version\fR on a multi-processor system).
-If \fBKEYWORD\fR is not provided or not valid, a list of all valid
+.nh
+.B processor\-version
+.hy
+on a multi-processor system).
+If \fIKEYWORD\fP is not provided or not valid, a list of all valid
keywords is printed and
.B dmidecode
exits with an error.
@@ -101,42 +127,56 @@ typically from files under
.IR /sys/devices/virtual/dmi/id .
Most of these files are even readable by regular users.
.TP
-.BR "-t" ", " "--type TYPE"
-Only display the entries of type \fBTYPE\fR. \fBTYPE\fR can be either a
+.BR "-t" ", " "--type \fITYPE\fP"
+Only display the entries of type \fITYPE\fP. It can be either a
\s-1DMI\s0 type number, or a comma-separated list of type numbers, or a
-keyword from the following list: \fBbios\fR, \fBsystem\fR,
-\fBbaseboard\fR, \fBchassis\fR, \fBprocessor\fR, \fBmemory\fR,
-\fBcache\fR, \fBconnector\fR, \fBslot\fR. Refer to the DMI TYPES section
-below for details.
+keyword from the following list:
+.nh
+.BR bios ,
+.BR system ,
+.BR baseboard ,
+.BR chassis ,
+.BR processor ,
+.BR memory ,
+.BR cache ,
+.BR connector ,
+.BR slot .
+.hy
+Refer to the DMI TYPES section below for details.
If this option is used more than once, the set of displayed entries will be
the union of all the given types.
-If \fBTYPE\fR is not provided or not valid, a list of all valid keywords
+If \fITYPE\fP is not provided or not valid, a list of all valid keywords
is printed and
.B dmidecode
exits with an error.
.TP
+.BR "-H" ", " "--handle \fIHANDLE\fP"
+Only display the entry whose handle matches \fIHANDLE\fP.
+\fIHANDLE\fP is a 16-bit integer.
+.TP
.BR "-u" ", " "--dump"
Do not decode the entries, dump their contents as hexadecimal instead.
Note that this is still a text output, no binary data will be thrown upon
you. The strings attached to each entry are displayed as both
hexadecimal and \s-1ASCII\s0. This option is mainly useful for debugging.
.TP
-.BR " " " " "--dump-bin FILE"
+.BR " " " " "--dump-bin \fIFILE\fP"
Do not decode the entries, instead dump the DMI data to a file in binary
-form. The generated file is suitable to pass to \fB--from-dump\fR
+form. The generated file is suitable to pass to \fB--from-dump\fP
later.
+\fIFILE\fP must not exist.
.TP
-.BR " " " " "--from-dump FILE"
-Read the DMI data from a binary file previously generated using
-\fB--dump-bin\fR.
+.BR " " " " "--from-dump \fIFILE\fP"
+Read the DMI data from a binary file previously generated using
+\fB--dump-bin\fP.
.TP
.BR " " " " "--no-sysfs"
Do not attempt to read DMI data from sysfs files. This is mainly useful for
debugging.
.TP
-.BR " " " " "--oem-string N"
-Only display the value of the \s-1OEM\s0 string number \fBN\fR. The first
-\s-1OEM\s0 string has number 1. With special value "count", return the
+.BR " " " " "--oem-string \fIN\fP"
+Only display the value of the \s-1OEM\s0 string number \fIN\fP. The first
+\s-1OEM\s0 string has number \fB1\fP. With special value \fBcount\fP, return the
number of OEM strings instead.
.TP
.BR "-h" ", " "--help"
@@ -145,7 +185,10 @@ Display usage information and exit
.BR "-V" ", " "--version"
Display the version and exit
.P
-Options --string, --type, --dump-bin and --oem-string
+Options
+.BR --string ,
+.BR --type,
+.BR --dump-bin " and " --oem-string
determine the output format and are mutually exclusive.
.P
Please note in case of
@@ -154,10 +197,9 @@ is run on a system with BIOS that boasts new SMBIOS specification, which
is not supported by the tool yet, it will print out relevant message in
addition to requested data on the very top of the output. Thus informs the
output data is not reliable.
-
+.\"
.SH "DMI TYPES"
The \s-1SMBIOS\s0 specification defines the following \s-1DMI\s0 types:
-
.TS
r l
__
@@ -214,7 +256,7 @@ end-of-table marker. Types 128 to 255 are for \s-1OEM\s0-specific data.
will display these entries by default, but it can only decode them
when the vendors have contributed documentation or code for them.
-Keywords can be used instead of type numbers with \fB--type\fR.
+Keywords can be used instead of type numbers with \fB--type\fP.
Each keyword is equivalent to a list of type numbers:
.TS
@@ -242,25 +284,46 @@ dmidecode --type 0,13
dmidecode --type bios
.IP \(bu
dmidecode --type BIOS
-
+.\"
.SH BINARY DUMP FILE FORMAT
-The binary dump files generated by --dump-bin and read using --from-dump
+The binary dump files generated by \fB--dump-bin\fP and read using \fB--from-dump\fP
are formatted as follows:
.IP \(bu "\w'\(bu'u+1n"
The SMBIOS or DMI entry point is located at offset 0x00.
It is crafted to hard-code the table address at offset 0x20.
.IP \(bu "\w'\(bu'u+1n"
The DMI table is located at offset 0x20.
-
+.\"
+.SH UUID FORMAT
+There is some ambiguity about how to interpret the UUID fields prior to SMBIOS
+specification version 2.6. There was no mention of byte swapping, and RFC 4122
+says that no byte swapping should be applied by default. However, SMBIOS
+specification version 2.6 (and later) explicitly states that the first 3 fields
+of the UUID should be read as little-endian numbers (byte-swapped).
+Furthermore, it implies that the same was already true for older versions of
+the specification, even though it was not mentioned. In practice, many hardware
+vendors were not byte-swapping the UUID. So, in order to preserve
+compatibility, it was decided to interpret the UUID fields according to RFC
+4122 (no byte swapping) when the SMBIOS version is older than 2.6, and to
+interpret the first 3 fields as little-endian (byte-swapped) when the SMBIOS
+version is 2.6 or later. The Linux kernel follows the same logic.
+.\"
.SH FILES
.I /dev/mem
-.I /sys/firmware/dmi/tables/smbios_entry_point (Linux only)
-.I /sys/firmware/dmi/tables/DMI (Linux only)
+.br
+.I /sys/firmware/dmi/tables/smbios_entry_point
+(Linux only)
+.br
+.I /sys/firmware/dmi/tables/DMI
+(Linux only)
+.\"
.SH BUGS
More often than not, information contained in the \s-1DMI\s0 tables is inaccurate,
incomplete or simply wrong.
+.\"
.SH AUTHORS
Alan Cox, Jean Delvare
+.\"
.SH "SEE ALSO"
.BR biosdecode (8),
.BR mem (4),
diff --git a/man/ownership.8 b/man/ownership.8
index f24ef94..2742300 100644
--- a/man/ownership.8
+++ b/man/ownership.8
@@ -1,10 +1,12 @@
.TH OWNERSHIP 8 "February 2005" "dmidecode"
+.\"
.SH NAME
ownership \- Compaq ownership tag retriever
+.\"
.SH SYNOPSIS
.B ownership
-.RB [ OPTIONS ]
-
+.RI [ OPTIONS ]
+.\"
.SH DESCRIPTION
.B ownership
retrieves and prints the "ownership tag" that can be set on Compaq
@@ -14,22 +16,24 @@ package,
.B ownership
doesn't print any version information, nor labels, but only the raw
ownership tag. This should help its integration in scripts.
-
+.\"
.SH OPTIONS
.TP
-.BR "-d" ", " "--dev-mem FILE"
-Read memory from device \fBFILE\fR (default: \fB/dev/mem\fR)
+.BR "-d" ", " "--dev-mem \fIFILE\fP"
+Read memory from device \fIFILE\fP (default: \fI/dev/mem\fP)
.TP
.BR "-h" ", " "--help"
Display usage information and exit
.TP
.BR "-V" ", " "--version"
Display the version and exit
-
+.\"
.SH FILES
.I /dev/mem
+.\"
.SH AUTHOR
Jean Delvare
+.\"
.SH "SEE ALSO"
.BR biosdecode (8),
.BR dmidecode (8),
diff --git a/man/vpddecode.8 b/man/vpddecode.8
index c9e4acf..44901ad 100644
--- a/man/vpddecode.8
+++ b/man/vpddecode.8
@@ -1,10 +1,12 @@
.TH VPDDECODE 8 "February 2007" "dmidecode"
+.\"
.SH NAME
vpddecode \- \s-1VPD\s0 structure decoder
+.\"
.SH SYNOPSIS
.B vpddecode
-.RB [ OPTIONS ]
-
+.RI [ OPTIONS ]
+.\"
.SH DESCRIPTION
.B vpddecode
prints the "vital product data" information that can be found in almost
@@ -17,56 +19,61 @@ Box Serial Number
Motherboard Serial Number
.IP \(bu
Machine Type/Model
-
.PP
Some systems have these additional items:
.IP \(bu "\w'\(bu'u+1n"
BIOS Release Date
.IP \(bu
Default Flash Image File Name
-
.PP
Note that these additional items are not documented by IBM, so this is
guess work, and as such should not be blindly trusted. Feedback about
the accuracy of these labels is welcome.
-
+.\"
.SH OPTIONS
.TP
-.BR "-d" ", " "--dev-mem FILE"
-Read memory from device \fBFILE\fR (default: \fB/dev/mem\fR)
+.BR "-d" ", " "--dev-mem \fIFILE\fP"
+Read memory from device \fIFILE\fP (default: \fI/dev/mem\fP)
.TP
-.BR "-s" ", " "--string KEYWORD"
-Only display the value of the \s-1VPD\s0 string identified by \fBKEYWORD\fR.
-\fBKEYWORD\fR must be a keyword from the following list: \fBbios-build-id\fR,
-\fBbox-serial-number\fR, \fBmotherboard-serial-number\fR,
-\fBmachine-type-model\fR, \fBbios-release-date\fR.
+.BR "-s" ", " "--string \fIKEYWORD\fP"
+Only display the value of the \s-1VPD\s0 string identified by \fIKEYWORD\fP.
+It must be a keyword from the following list:
+.nh
+.BR bios-build-id ,
+.BR box-serial-number ,
+.BR motherboard-serial-number ,
+.BR machine-type-model ,
+.BR bios-release-date .
+.hy
Each keyword corresponds to an offset and a length within the \s-1VPD\s0
record.
Not all strings may be defined on all \s-1VPD\s0-enabled systems.
-If \fBKEYWORD\fR is not provided or not valid, a list of all valid
+If \fIKEYWORD\fP is not provided or not valid, a list of all valid
keywords is printed and
.B vpddecode
exits with an error.
This option cannot be used more than once.
-Mutually exclusive with \fB--dump\fR.
+Mutually exclusive with \fB--dump\fP.
.TP
.BR "-u" ", " "--dump"
Do not decode the VPD records, dump their contents as hexadecimal instead.
Note that this is still a text output, no binary data will be thrown upon
you. ASCII equivalent is displayed when possible. This option is mainly
useful for debugging.
-Mutually exclusive with \fB--string\fR.
+Mutually exclusive with \fB--string\fP.
.TP
.BR "-h" ", " "--help"
Display usage information and exit
.TP
.BR "-V" ", " "--version"
Display the version and exit
-
+.\"
.SH FILES
.I /dev/mem
+.\"
.SH AUTHOR
Jean Delvare
+.\"
.SH "SEE ALSO"
.BR biosdecode (8),
.BR dmidecode (8),
diff --git a/types.h b/types.h
index 19d803d..51c32d7 100644
--- a/types.h
+++ b/types.h
@@ -11,8 +11,7 @@ typedef unsigned int u32;
/*
* You may use the following defines to adjust the type definitions
* depending on the architecture:
- * - Define BIGENDIAN on big-endian systems. Untested, as all target
- * systems to date are little-endian.
+ * - Define BIGENDIAN on big-endian systems.
* - Define ALIGNMENT_WORKAROUND if your system doesn't support
* non-aligned memory access. In this case, we use a slower, but safer,
* memory access method. This should be done automatically in config.h
@@ -31,7 +30,7 @@ typedef struct {
} u64;
#endif
-#ifdef ALIGNMENT_WORKAROUND
+#if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN)
static inline u64 U64(u32 low, u32 high)
{
u64 self;
@@ -43,20 +42,18 @@ static inline u64 U64(u32 low, u32 high)
}
#endif
-#ifdef ALIGNMENT_WORKAROUND
-# ifdef BIGENDIAN
-# define WORD(x) (u16)((x)[1] + ((x)[0] << 8))
-# define DWORD(x) (u32)((x)[3] + ((x)[2] << 8) + ((x)[1] << 16) + ((x)[0] << 24))
-# define QWORD(x) (U64(DWORD(x + 4), DWORD(x)))
-# else /* BIGENDIAN */
-# define WORD(x) (u16)((x)[0] + ((x)[1] << 8))
-# define DWORD(x) (u32)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24))
-# define QWORD(x) (U64(DWORD(x), DWORD(x + 4)))
-# endif /* BIGENDIAN */
-#else /* ALIGNMENT_WORKAROUND */
+/*
+ * Per SMBIOS v2.8.0 and later, all structures assume a little-endian
+ * ordering convention.
+ */
+#if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN)
+#define WORD(x) (u16)((x)[0] + ((x)[1] << 8))
+#define DWORD(x) (u32)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24))
+#define QWORD(x) (U64(DWORD(x), DWORD(x + 4)))
+#else /* ALIGNMENT_WORKAROUND || BIGENDIAN */
#define WORD(x) (u16)(*(const u16 *)(x))
#define DWORD(x) (u32)(*(const u32 *)(x))
#define QWORD(x) (*(const u64 *)(x))
-#endif /* ALIGNMENT_WORKAROUND */
+#endif /* ALIGNMENT_WORKAROUND || BIGENDIAN */
#endif
diff --git a/util.c b/util.c
index 0aafcb1..2770b1d 100644
--- a/util.c
+++ b/util.c
@@ -2,7 +2,7 @@
* Common "util" functions
* This file is part of the dmidecode project.
*
- * Copyright (C) 2002-2017 Jean Delvare <jdelvare@suse.de>
+ * Copyright (C) 2002-2018 Jean Delvare <jdelvare@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -59,7 +59,6 @@ static int myread(int fd, u8 *buf, size_t count, const char *prefix)
{
if (errno != EINTR)
{
- close(fd);
perror(prefix);
return -1;
}
@@ -70,7 +69,6 @@ static int myread(int fd, u8 *buf, size_t count, const char *prefix)
if (r2 != count)
{
- close(fd);
fprintf(stderr, "%s: Unexpected end of file\n", prefix);
return -1;
}
@@ -90,19 +88,17 @@ int checksum(const u8 *buf, size_t len)
/*
* Reads all of file from given offset, up to max_len bytes.
- * A buffer of max_len bytes is allocated by this function, and
+ * A buffer of at most max_len bytes is allocated by this function, and
* needs to be freed by the caller.
* This provides a similar usage model to mem_chunk()
*
- * Returns pointer to buffer of max_len bytes, or NULL on error, and
+ * Returns a pointer to the allocated buffer, or NULL on error, and
* sets max_len to the length actually read.
- *
*/
void *read_file(off_t base, size_t *max_len, const char *filename)
{
+ struct stat statbuf;
int fd;
- size_t r2 = 0;
- ssize_t r;
u8 *p;
/*
@@ -116,12 +112,20 @@ void *read_file(off_t base, size_t *max_len, const char *filename)
return NULL;
}
- if (lseek(fd, base, SEEK_SET) == -1)
+ /*
+ * Check file size, don't allocate more than can be read.
+ */
+ if (fstat(fd, &statbuf) == 0)
{
- fprintf(stderr, "%s: ", filename);
- perror("lseek");
- p = NULL;
- goto out;
+ if (base >= statbuf.st_size)
+ {
+ fprintf(stderr, "%s: Can't read data beyond EOF\n",
+ filename);
+ p = NULL;
+ goto out;
+ }
+ if (*max_len > (size_t)statbuf.st_size - base)
+ *max_len = statbuf.st_size - base;
}
if ((p = malloc(*max_len)) == NULL)
@@ -130,49 +134,67 @@ void *read_file(off_t base, size_t *max_len, const char *filename)
goto out;
}
- do
+ if (lseek(fd, base, SEEK_SET) == -1)
{
- r = read(fd, p + r2, *max_len - r2);
- if (r == -1)
- {
- if (errno != EINTR)
- {
- perror(filename);
- free(p);
- p = NULL;
- goto out;
- }
- }
- else
- r2 += r;
+ fprintf(stderr, "%s: ", filename);
+ perror("lseek");
+ goto err_free;
}
- while (r != 0);
- *max_len = r2;
+ if (myread(fd, p, *max_len, filename) == 0)
+ goto out;
+
+err_free:
+ free(p);
+ p = NULL;
+
out:
- close(fd);
+ if (close(fd) == -1)
+ perror(filename);
return p;
}
+#ifdef USE_MMAP
+static void safe_memcpy(void *dest, const void *src, size_t n)
+{
+#ifdef USE_SLOW_MEMCPY
+ size_t i;
+
+ for (i = 0; i < n; i++)
+ *((u8 *)dest + i) = *((const u8 *)src + i);
+#else
+ memcpy(dest, src, n);
+#endif /* USE_SLOW_MEMCPY */
+}
+#endif /* USE_MMAP */
+
/*
* Copy a physical memory chunk into a memory buffer.
* This function allocates memory.
*/
void *mem_chunk(off_t base, size_t len, const char *devmem)
{
- void *p;
+ struct stat statbuf;
+ void *p = NULL;
int fd;
#ifdef USE_MMAP
- struct stat statbuf;
off_t mmoffset;
void *mmp;
#endif
- if ((fd = open(devmem, O_RDONLY)) == -1)
+ /*
+ * Safety check: if running as root, devmem is expected to be a
+ * character device file.
+ */
+ if ((fd = open(devmem, O_RDONLY)) == -1
+ || fstat(fd, &statbuf) == -1
+ || (geteuid() == 0 && !S_ISCHR(statbuf.st_mode)))
{
- perror(devmem);
- return NULL;
+ fprintf(stderr, "Can't read memory from %s\n", devmem);
+ if (fd == -1)
+ return NULL;
+ goto out;
}
if ((p = malloc(len)) == NULL)
@@ -182,13 +204,6 @@ void *mem_chunk(off_t base, size_t len, const char *devmem)
}
#ifdef USE_MMAP
- if (fstat(fd, &statbuf) == -1)
- {
- fprintf(stderr, "%s: ", devmem);
- perror("stat");
- goto err_free;
- }
-
/*
* mmap() will fail with SIGBUS if trying to map beyond the end of
* the file.
@@ -214,7 +229,7 @@ void *mem_chunk(off_t base, size_t len, const char *devmem)
if (mmp == MAP_FAILED)
goto try_read;
- memcpy(p, (u8 *)mmp + mmoffset, len);
+ safe_memcpy(p, (u8 *)mmp + mmoffset, len);
if (munmap(mmp, mmoffset + len) == -1)
{
@@ -247,46 +262,6 @@ out:
return p;
}
-int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add)
-{
- FILE *f;
-
- f = fopen(dumpfile, add ? "r+b" : "wb");
- if (!f)
- {
- fprintf(stderr, "%s: ", dumpfile);
- perror("fopen");
- return -1;
- }
-
- if (fseek(f, base, SEEK_SET) != 0)
- {
- fprintf(stderr, "%s: ", dumpfile);
- perror("fseek");
- goto err_close;
- }
-
- if (fwrite(data, len, 1, f) != 1)
- {
- fprintf(stderr, "%s: ", dumpfile);
- perror("fwrite");
- goto err_close;
- }
-
- if (fclose(f))
- {
- fprintf(stderr, "%s: ", dumpfile);
- perror("fclose");
- return -1;
- }
-
- return 0;
-
-err_close:
- fclose(f);
- return -1;
-}
-
/* Returns end - start + 1, assuming start < end */
u64 u64_range(u64 start, u64 end)
{
diff --git a/util.h b/util.h
index 3094cf8..ef24eb9 100644
--- a/util.h
+++ b/util.h
@@ -27,5 +27,4 @@
int checksum(const u8 *buf, size_t len);
void *read_file(off_t base, size_t *len, const char *filename);
void *mem_chunk(off_t base, size_t len, const char *devmem);
-int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add);
u64 u64_range(u64 start, u64 end);
diff --git a/version.h b/version.h
index 778ae5f..179ab30 100644
--- a/version.h
+++ b/version.h
@@ -1 +1 @@
-#define VERSION "3.1"
+#define VERSION "3.5"