Imported Upstream version 2.11 upstream upstream/2.11
authorAnas Nashif <anas.nashif@intel.com>
Wed, 6 Mar 2013 10:01:10 +0000 (02:01 -0800)
committerAnas Nashif <anas.nashif@intel.com>
Wed, 6 Mar 2013 10:01:10 +0000 (02:01 -0800)
25 files changed:
AUTHORS [new file with mode: 0644]
CHANGELOG [new file with mode: 0644]
LICENSE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
biosdecode.c [new file with mode: 0644]
config.h [new file with mode: 0644]
dmidecode.c [new file with mode: 0644]
dmidecode.h [new file with mode: 0644]
dmioem.c [new file with mode: 0644]
dmioem.h [new file with mode: 0644]
dmiopt.c [new file with mode: 0644]
dmiopt.h [new file with mode: 0644]
man/biosdecode.8 [new file with mode: 0644]
man/dmidecode.8 [new file with mode: 0644]
man/ownership.8 [new file with mode: 0644]
man/vpddecode.8 [new file with mode: 0644]
ownership.c [new file with mode: 0644]
types.h [new file with mode: 0644]
util.c [new file with mode: 0644]
util.h [new file with mode: 0644]
version.h [new file with mode: 0644]
vpddecode.c [new file with mode: 0644]
vpdopt.c [new file with mode: 0644]
vpdopt.h [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..7ec5a51
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,83 @@
+DEVELOPER AND MAINTAINER
+Anton Arapov <anton@redhat.com>
+
+ORIGINAL AUTHORS
+Alan Cox <alan@redhat.com>
+Jean Delvare <khali@linux-fr.org>
+
+CODE CONTRIBUTORS (IN CHRONOLOGICAL ORDER)
+Matt Domsch <Matt_Domsch@dell.com>
+Arjan van de Ven <arjanv@redhat.com>
+Mark D. Studebaker <mds@paradyne.com>
+Larry Lile <llile@dreamworks.com>
+Dave Johnson <ddj@cascv.brown.edu>
+Petter Reinholdtsen <pere@hungry.com>
+Roberto Nibali <ratz@tac.ch>
+John Cagle <jcagle@kernel.org>
+Jens Elkner <elkner@linofee.org>
+Jarod Wilson <jarod@redhat.com>
+
+MANY THANKS TO (IN CHRONOLOGICAL ORDER)
+Werner Heuser
+Alexandre Duret-Lutz
+Xavier Roche
+Pamela Huntley
+Gael Stephan
+Sebastian Henschel
+Richard Sharpe
+David Wilson
+Glen Foster
+Chad Smith
+Joshua Goldenhar
+Luc Van de Velde
+Mario Lang
+Hugues Lepesant
+Sergey Leonovich
+Mike Cooper
+Marc Rieffel
+Jeff Moyer
+Josef Moellers
+Zing Zing Shishak
+Rafael Avila de Espindola
+Roger Koot
+Martin Pool
+Doug Brenner
+Alex Williamson
+Durval Menezes
+Raphael Raimbault
+Raul Nunez de Arenas Coronado
+Francois Revol
+Dominik Klein
+Erwan Velu
+Don Howard
+Frans Pop
+Tomek Mateja
+Myke Olson
+Torsten Seemann
+Garry Belka
+Klaus Muth
+Antoine Fuselier
+Matthew Garrett
+Landry Breuil
+Luke Suchocki
+Attila Nagy
+Alex Iribarren
+Sebastien Douche
+William Lallemand
+Olivier Guerrier
+Pascal Terjan
+Stuart Hayes
+Sofian Brabez
+Vincent Pelletier
+Andreas Gruenbacher
+Lin Li
+Thomas Hiller
+Paul Flo Williams
+Olof Johansson
+Alexandre Lissy
+Michal Svec
+Vojtech Pavlik
+Murlin Wenzel
+Harald Mueller-Ney
+Lars Mueller
+Thomas Mingarelli
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644 (file)
index 0000000..0545f8a
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,1335 @@
+2010-11-24  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Fix decoding of IPMI base address LSB.
+
+2010-11-09  Jean Delvare  <khali@linux-fr.org>
+
+       * dmidecode.c: Drop redundant/obsolete references to
+         CIM_Processor.Family.
+
+2010-10-26  Jean Delvare  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Warn if decoding an SMBIOS implementation which is
+         newer than what we support.
+
+2009-04-04  Jean Delvare  <khali@linux-fr.org>
+
+       * Makefile: Clarify license.
+
+2008-11-23  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Handle chassis information records of size 19
+         (DMI type 3).
+
+2008-11-10  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Add missing colon to temperature probe label.
+         Patch from Alex Iribarren.
+
+2008-02-16  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * Makefile: Fix the uninstall-man target.
+
+2007-06-07  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * biosdecode.c: Fix a compilation error with non-C99 compilers.
+         Patch from Francois Revol.
+
+2007-02-26  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Fix typo reported by David Wilson (DMI case 3).
+
+2006-02-04  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * Makefile: Use -Wundef.
+
+2005-08-31  Jean Delvare  <khali@linux-fr.org>
+
+       * dmidecode.c: Drop trailing dot from handle description line.
+
+2005-08-29  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmiopt.c, dmidecode.8: Options --dump and --quiet are mutually
+         exclusive.
+
+2005-06-23  Jean Delvare  <khali@linux-fr.org>
+
+       * dmiopt.c, dmidecode.8: Options --dump and --string are mutually
+         exclusive.
+
+2005-06-22  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.8: Document the new -t, --type option.
+
+2005-06-15  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Add option -t, --type. It limits the output to
+         the given type(s) of DMI entries.
+
+2005-05-25  Jean Delvare  <khali@linux-fr.org>
+
+       * vpddecode.c: Add product IDs "KE", "NT" and "ZR". Reported by
+         Bernd Krumboeck.
+
+2005-05-15  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * Makefile: Use variables for install and rm commands, so that these
+         can be overridden by the caller.
+
+2005-03-25  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * version.h: Set version to 2.6.
+       * Makefile: ownership.o depends on version.h.
+
+2005-02-24  Jean Delvare  <khali@linux-fr.org>
+
+       * vpddecode.c: Add product ID "2C". Reported by Tomek Mateja.
+
+2005-02-17  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * util.c: Fix incorrect length in munmap call.
+       * Makefile: Use -Wmissing-prototypes.
+       * dmidecode.c: Fix maximum battery error value.
+
+2005-02-11  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * vpddecode.c: Add product IDs "AP", "KP" and "RD". Reported by
+         David Rosala.
+
+2005-01-17  Jean Delvare  <khali@linux-fr.org>
+
+       * README: Add a note about Cygwin. Thanks to Dominik Klein for
+         reporting success.
+
+2004-12-10  Jean Delvare  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * util.c, util.h: Function myread has no more user outside of util.c.
+       * biosdecode.c: Speed improvements.
+
+2004-11-20  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * vpddecode.c: Update product ID "1R". Reported by Marco Wertejuk.
+
+2004-10-24  Jean Delvare  <khali@linux-fr.org>
+
+       * util.c: Workaround missing MAP_FAILED definition, needed on
+         old systems. Original patch from Durval Menezes.
+
+2004-10-14  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * util.c: Add missing header include.
+
+2004-06-11  Jean Delvare  <khali@linux-fr.org>
+
+       * vpddecode.c: Add product IDs "GE" and "T2". Reported by Doug Brenner.
+
+2004-05-02  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * vpddecode.c: Add product ID "JP". Reported by Bernd Krumboeck.
+
+2004-04-22  Jean Delvare  <khali@linux-fr.org>
+
+       * dmidecode.c, biosdecode.c, ownership.c, types.h: Move common
+         WORD-like macros to types.h.
+
+2004-04-21  Jean Delvare  <khali@linux-fr.org>
+
+       * dmidecode.c, biosdecode.c: Fix my contact information.
+       * dmidecode.c: Update copyright year.
+
+2004-04-20  Jean Delvare  <khali@linux-fr.org>
+
+       * README: Correct Chad Smith's name. Reported by Martin Pool.
+
+2004-04-15  Jean Delvare  <khali@linux-fr.org>
+
+       * vpddecode.c: Add product ID "PL". Reported by Mark Syms.
+
+2004-04-14  Jean Delvare  <khali@linux-fr.org>
+
+       * vpddecode.c: Add product ID "PD". Reported by Roger Koot.
+
+2004-04-11  Jean Delvare  <khali@linux-fr.org>
+
+       * dmidecode.c, Makefile, README: Drop TABLE_LITTLEENDIAN.
+       * README: Update manual pages information.
+
+2004-04-02  Jean Delvare  <khali@linux-fr.org>
+
+       * vpddecode.c: Add product ID "NV". Reported by Shawn Starr.
+
+2004-03-27  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * vpddecode.c: Add product ID "2A". Reported by Rafael Avila
+         de Espindola.
+       * version.h: Set version to 2.4.
+
+2004-03-07  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * README: Update.
+
+2004-02-25  Jean Delvare  <khali@linux-fr.org>
+
+       * dmidecode.c: Support CPUID document revision 25 (no change).
+       * dmidecode.c: Shorten the EOF error message.
+
+2004-02-23  Jean Delvare  <khali@linux-fr.org>
+
+       * man/biosdecode.8, man/dmidecode.8, man/ownership.8,
+         man/vpddecode.8: New.
+       * Makefile: Handle new manual pages.
+
+2003-12-28  Jean Delvare  <khali@linux-fr.org>
+
+       * vpddecode.c: Add product ID "PT". Reported by Ramiro Barreiro.
+
+2003-12-17  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Automatically detect architectures on which to use EFI
+         (ia64 for now). Suggested by Jeff Moyer.
+
+2003-11-11  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Add another exception to the CPUID-supporting CPU list.
+
+2003-10-19  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * ownership.c: Fix a harmless warning on x86_64. Reported by Mike
+         Cooper.
+
+2003-09-19  Jean Delvare  <khali@linux-fr.org>
+
+       * dmidecode.c: Explicitly say when no SMBIOS nor DMI entry point
+         was found. Implicitly suggested by Sergey Leonovich.
+
+2003-09-11  Jean Delvare  <khali@linux-fr.org>
+
+       * Makefile: Don't use $^ since it isn't supported by BSD make.
+         Reported by Hugues Lepesant.
+
+2003-09-05  Jean Delvare  <khali@linux-fr.org>
+
+       * Makefile: Fix missing ownership dependency for install target.
+         Reported by Mario Lang.
+
+2003-08-08  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * biosdecode.c: Better display of Compaq-specific entries (thank to
+         some documentation).
+
+2003-06-25  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Add support for IA-64.
+       * Makefile: Add new option CFLAGS modifier lines for IA-64.
+
+2003-06-17  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Fix typo in IPMI register spacing table.
+       * version.h: Set version to 2.1.
+
+2003-06-04  Jean Delvare  <khali@linux-fr.org>
+
+       * Makefile: Restore optional CFLAGS modifier lines.
+       * README: New.
+
+2003-05-30  Jean Delvare  <khali@linux-fr.org>
+
+       * dmidecode.c: Cleaner handling of unreachable table.
+
+2003-05-27  Jean Delvare  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       * dmidecode.c: Fix typo reported by David Wilson (DMI case 6).
+
+2003-03-08  Jean Delvare  <khali@linux-fr.org>
+
+       * dmidecode.c: Decode more fields according to the IPMI specification
+         (DMI case 38).
+
+2003-03-07  Jean Delvare  <khali@linux-fr.org>
+
+       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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Fix bad index in DMI case 27 (cooling device).
+
+2002-10-14  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * dmidecode.c: Fix maximum cache size and installed size being
+         inverted.
+       * dmidecode.c: Fix typos in port types.
+
+2002-10-10  Jean Delvare  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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  <khali@linux-fr.org>
+
+       * 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/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..5b6e7c6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..55378bb
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,140 @@
+#
+#   DMI Decode
+#   BIOS Decode
+#   VPD Decode
+#
+#   Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
+#   Copyright (C) 2002-2007 Jean Delvare <khali@linux-fr.org>
+#
+#   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.
+#
+
+CC      = gcc
+CFLAGS  = -W -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual \
+          -Wcast-align -Wwrite-strings -Wmissing-prototypes -Winline -Wundef
+#CFLAGS += -DBIGENDIAN
+#CFLAGS += -DALIGNMENT_WORKAROUND
+
+# When debugging, disable -O2 and enable -g.
+CFLAGS += -O2
+#CFLAGS += -g
+
+# Pass linker flags here
+LDFLAGS =
+
+DESTDIR =
+prefix  = /usr/local
+sbindir = $(prefix)/sbin
+mandir  = $(prefix)/share/man
+man8dir = $(mandir)/man8
+docdir  = $(prefix)/share/doc/dmidecode
+
+INSTALL         := install
+INSTALL_DATA    := $(INSTALL) -m 644
+INSTALL_DIR     := $(INSTALL) -m 755 -d
+INSTALL_PROGRAM := $(INSTALL) -m 755
+RM              := rm -f
+
+# BSD make provides $MACHINE, but GNU make doesn't
+MACHINE ?= $(shell uname -m 2>/dev/null)
+
+# These programs are only useful on x86
+PROGRAMS-i386 := biosdecode ownership vpddecode
+PROGRAMS-i486 := $(PROGRAMS-i386)
+PROGRAMS-i586 := $(PROGRAMS-i386)
+PROGRAMS-i686 := $(PROGRAMS-i386)
+PROGRAMS-x86_64 := biosdecode ownership vpddecode
+PROGRAMS-amd64 := $(PROGRAMS-x86_64)
+
+PROGRAMS := dmidecode $(PROGRAMS-$(MACHINE))
+
+all : $(PROGRAMS)
+
+#
+# Programs
+#
+
+dmidecode : dmidecode.o dmiopt.o dmioem.o util.o
+       $(CC) $(LDFLAGS) dmidecode.o dmiopt.o dmioem.o util.o -o $@
+
+biosdecode : biosdecode.o util.o
+       $(CC) $(LDFLAGS) biosdecode.o util.o -o $@
+
+ownership : ownership.o util.o
+       $(CC) $(LDFLAGS) ownership.o util.o -o $@
+
+vpddecode : vpddecode.o vpdopt.o util.o
+       $(CC) $(LDFLAGS) vpddecode.o vpdopt.o util.o -o $@
+
+#
+# Objects
+#
+
+dmidecode.o : dmidecode.c version.h types.h util.h config.h dmidecode.h \
+             dmiopt.h dmioem.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
+       $(CC) $(CFLAGS) -c $< -o $@
+
+biosdecode.o : biosdecode.c version.h types.h util.h config.h 
+       $(CC) $(CFLAGS) -c $< -o $@
+
+ownership.o : ownership.c version.h types.h util.h config.h
+       $(CC) $(CFLAGS) -c $< -o $@
+
+vpddecode.o : vpddecode.c version.h types.h util.h config.h vpdopt.h
+       $(CC) $(CFLAGS) -c $< -o $@
+
+vpdopt.o : vpdopt.c config.h util.h vpdopt.h
+       $(CC) $(CFLAGS) -c $< -o $@
+
+util.o : util.c types.h util.h config.h
+       $(CC) $(CFLAGS) -c $< -o $@
+
+#
+# Commands
+#
+
+strip : $(PROGRAMS)
+       strip $(PROGRAMS)
+
+install : install-bin install-man install-doc
+
+uninstall : uninstall-bin uninstall-man uninstall-doc
+
+install-bin : $(PROGRAMS)
+       $(INSTALL_DIR) $(DESTDIR)$(sbindir)
+       for program in $(PROGRAMS) ; do \
+       $(INSTALL_PROGRAM) $$program $(DESTDIR)$(sbindir) ; done
+
+uninstall-bin :
+       for program in $(PROGRAMS) ; do \
+       $(RM) $(DESTDIR)$(sbindir)/$$program ; done
+
+install-man :
+       $(INSTALL_DIR) $(DESTDIR)$(man8dir)
+       for program in $(PROGRAMS) ; do \
+       $(INSTALL_DATA) man/$$program.8 $(DESTDIR)$(man8dir) ; done
+
+uninstall-man :
+       for program in $(PROGRAMS) ; do \
+       $(RM) $(DESTDIR)$(man8dir)/$$program.8 ; done
+
+install-doc :
+       $(INSTALL_DIR) $(DESTDIR)$(docdir)
+       $(INSTALL_DATA) README $(DESTDIR)$(docdir)
+       $(INSTALL_DATA) CHANGELOG $(DESTDIR)$(docdir)
+       $(INSTALL_DATA) AUTHORS $(DESTDIR)$(docdir)
+
+uninstall-doc :
+       $(RM) -r $(DESTDIR)$(docdir)
+
+clean :
+       $(RM) *.o $(PROGRAMS) core
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..391a5cb
--- /dev/null
+++ b/README
@@ -0,0 +1,116 @@
+** INTRODUCTION **
+
+Dmidecode reports information about your system's hardware as described in
+your system BIOS according to the SMBIOS/DMI standard. This information
+typically includes system manufacturer, model name, serial number, BIOS
+version, asset tag as well as a lot of other details of varying level of
+interest and reliability depending on the manufacturer. This will often
+include usage status for the CPU sockets, expansion slots (e.g. AGP, PCI,
+ISA) and memory module slots, and the list of I/O ports (e.g. serial,
+parallel, USB).
+
+DMI data can be used to enable or disable specific portions of kernel code
+depending on the specific hardware. Thus, one use of dmidecode is for kernel
+developers to detect system "signatures" and add them to the kernel source
+code when needed.
+
+Beware that DMI data have proven to be too unreliable to be blindly trusted.
+Dmidecode does not scan your hardware, it only reports what the BIOS told it
+to.
+
+
+** INSTALLATION **
+
+The home web page for dmidecode is hosted on Savannah:
+  http://www.nongnu.org/dmidecode/
+You will find the latest version (including CVS) there, as well as fresh news
+and other interesting material, such as a list of related projects and
+articles.
+
+This program was first written for Linux, and has since been reported to work
+on FreeBSD, NetBSD, OpenBSD, BeOS, Cygwin and Solaris as well.
+
+There's no configure script, so simply run "make" to build dmidecode, and
+"make install" to install it. You also can use "make uninstall" to remove
+all the files you installed. By default, files are installed in /usr/local
+but you can change this behavior by editing the Makefile file and setting
+prefix to wherever you want. You may change the C compiler and the
+compilation flags as well.
+
+Optionally, you can run "make strip" prior to "make install" if you want
+smaller binaries. However, be aware that this will prevent any further
+attempt to debug the programs.
+
+Two parameters can be set in the Makefile file to make dmidecode work on
+non-i386 systems. They should be used if your system uses the big endian
+byte ordering (Motorola) or doesn't support unaligned memory accesses,
+respectively. For example, compiling for a SPARC processor would require
+both (but I am not aware of SPARC-based systems implementing SMBIOS).
+Compiling for an IA64 processor requires the memory alignment workaround,
+and it is enabled automatically.
+
+
+** DOCUMENTATION **
+
+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.
+
+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.
+Have a look at the AUTHORS file and contact one of the maintainers.
+
+If you want to help with the development of dmidecode, please consider
+joining the dmidecode-devel discussion list:
+  http://lists.nongnu.org/mailman/listinfo/dmidecode-devel
+
+
+** COMMON PROBLEMS **
+
+IA-64
+
+Non-Linux systems are not yet supported.
+
+MMAP
+
+Note that mmap() is now used by default wherever possible, since this seems
+to solve a number of problems. This default behavior can be changed in
+config.h. Just to make sure this is clear, mmap() is not used for performance
+reasons but to increase the number of systems on which dmidecode can be
+successfully run.
+
+CYGWIN
+
+Dmidecode was reported to work under Cygwin. It seems that /dev/mem doesn't
+work properly before version 1.5.10 though, so you will need to use at least
+this version.
+
+
+** MISCELLANEOUS TOOLS **
+
+Three other tools come along with dmidecode: biosdecode, ownership and
+vpddecode. These tools are only useful on systems with a BIOS, so they
+are not built on IA-64 by default.
+
+BIOSDECODE
+
+This one prints all BIOS related information it can find in /dev/mem.
+It used to be part of dmidecode itself, but as dmidecode was growing,
+we felt that the non-DMI part had to be moved to a separate tool.
+
+OWNERSHIP
+
+This tool was written on a request by Luc Van de Velde for use with Novell
+tools in his company. It retrieves the "ownership tag" that can be set on
+most Compaq computers. Since it uses the same mechanisms dmidecode and
+biosdecode use, and could be of some use for other people as well, we
+decided to make it part of the project.
+
+VPDDECODE
+
+This tool prints the contents of the "vital product data" structure as
+found in most IBM and Lenovo computers. It used to have a lookup table
+for the machine name, but it was unreliable and hard to maintain so it
+was ultimately dropped. It has a command line interface.
diff --git a/biosdecode.c b/biosdecode.c
new file mode 100644 (file)
index 0000000..09acb43
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ * BIOS Decode
+ *
+ *   Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
+ *   Copyright (C) 2002-2008 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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
+ *
+ *   For the avoidance of doubt the "preferred form" of this code is one which
+ *   is in an open unpatent encumbered format. Where cryptographic key signing
+ *   forms part of the process of creating an executable the information
+ *   including keys needed to generate an equivalently functional executable
+ *   are deemed to be part of the source code.
+ *
+ * References:
+ *  - DMTF "System Management BIOS Reference Specification"
+ *    Version 2.3.4
+ *    http://www.dmtf.org/standards/smbios
+ *     - Intel "Preboot Execution Environment (PXE) Specification"
+ *    Version 2.1
+ *    http://www.intel.com/labs/manage/wfm/wfmspecs.htm
+ *  - ACPI "Advanced Configuration and Power Interface Specification"
+ *    Revision 2.0
+ *    http://www.acpi.info/spec20.htm
+ *  - Phoenix "BIOS32 Service Directory"
+ *    Revision 0.4
+ *    http://www.phoenix.com/en/support/white+papers-specs/
+ *  - Microsoft "Plug and Play BIOS Specification"
+ *    Version 1.0A
+ *    http://www.microsoft.com/hwdev/tech/PnP/
+ *  - Microsoft "PCI IRQ Routing Table Specification"
+ *    Version 1.0
+ *    http://www.microsoft.com/hwdev/archive/BUSBIOS/pciirq.asp
+ *  - Compaq "Technical Reference Guide for Compaq Deskpro 4000 and 6000"
+ *    First Edition
+ *    http://h18000.www1.hp.com/support/techpubs/technical_reference_guides/113a1097.html
+ *  - IBM "Using the BIOS Build ID to identify Thinkpad systems"
+ *    Revision 2005-09-19
+ *    http://www-307.ibm.com/pc/support/site.wss/MIGR-45120.html
+ *  - Fujitsu application panel technical details
+ *    As of July 23rd, 2004
+ *    http://apanel.sourceforge.net/tech.php
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "version.h"
+#include "config.h"
+#include "types.h"
+#include "util.h"
+
+/* Options are global */
+struct opt
+{
+       const char *devmem;
+       unsigned int flags;
+};
+static struct opt opt;
+
+#define FLAG_VERSION            (1 << 0)
+#define FLAG_HELP               (1 << 1)
+
+struct bios_entry {
+       const char *anchor;
+       size_t anchor_len; /* computed */
+       off_t low_address;
+       off_t high_address;
+       size_t (*length)(const u8 *);
+       int (*decode)(const u8*, size_t);
+};
+
+
+/*
+ * SMBIOS
+ */
+
+static size_t smbios_length(const u8 *p)
+{
+       return p[0x05] == 0x1E ? 0x1F : p[0x05];
+}
+
+static int smbios_decode(const u8 *p, size_t len)
+{
+       if (len < 0x1F || !checksum(p, p[0x05])
+        || memcmp("_DMI_", p + 0x10, 5) != 0
+        || !checksum(p + 0x10, 0x0F))
+               return 0;
+
+       printf("SMBIOS %u.%u present.\n",
+               p[0x06], p[0x07]);
+       printf("\tStructure Table Length: %u bytes\n",
+               WORD(p+0x16));
+       printf("\tStructure Table Address: 0x%08X\n",
+               DWORD(p + 0x18));
+       printf("\tNumber Of Structures: %u\n",
+               WORD(p + 0x1C));
+       printf("\tMaximum Structure Size: %u bytes\n",
+               WORD(p + 0x08));
+
+       return 1;
+}
+
+static size_t dmi_length(const u8 *p)
+{
+       (void) p;
+
+       return 0x0F;
+}
+
+static int dmi_decode(const u8 *p, size_t len)
+{
+       if (len < 0x0F || !checksum(p, len))
+               return 0;
+
+       printf("Legacy DMI %u.%u present.\n",
+               p[0x0E]>>4, p[0x0E] & 0x0F);
+       printf("\tStructure Table Length: %u bytes\n",
+               WORD(p + 0x06));
+       printf("\tStructure Table Address: 0x%08X\n",
+               DWORD(p + 0x08));
+       printf("\tNumber Of Structures: %u\n",
+               WORD(p + 0x0C));
+
+       return 1;
+}
+
+/*
+ * SYSID
+ */
+
+static size_t sysid_length(const u8 *p)
+{
+       return WORD(p + 0x08);
+}
+
+static int sysid_decode(const u8 *p, size_t len)
+{
+       if (len < 0x11 || !checksum(p, WORD(p + 0x08)))
+               return 0;
+
+       printf("SYSID present.\n");
+       printf("\tRevision: %u\n",
+               p[0x10]);
+       printf("\tStructure Table Address: 0x%08X\n",
+               DWORD(p + 0x0A));
+       printf("\tNumber Of Structures: %u\n",
+               WORD(p + 0x0E));
+
+       return 1;
+}
+
+/*
+ * PnP
+ */
+
+static size_t pnp_length(const u8 *p)
+{
+       return p[0x05];
+}
+
+static const char *pnp_event_notification(u8 code)
+{
+       static const char *notification[] = {
+               "Not Supported", /* 0x0 */
+               "Polling",
+               "Asynchronous",
+               "Unknown" /* 0x3 */
+       };
+
+       return notification[code];
+}
+
+static int pnp_decode(const u8 *p, size_t len)
+{
+       if (len < 0x21 || !checksum(p, p[0x05]))
+               return 0;
+
+       printf("PNP BIOS %u.%u present.\n",
+               p[0x04] >> 4, p[0x04] & 0x0F);
+       printf("\tEvent Notification: %s\n",
+               pnp_event_notification(WORD(p + 0x06) & 0x03));
+       if ((WORD(p + 0x06) & 0x03) == 0x01)
+               printf("\tEvent Notification Flag Address: 0x%08X\n",
+                       DWORD(p + 0x09));
+       printf("\tReal Mode 16-bit Code Address: %04X:%04X\n",
+               WORD(p + 0x0F), WORD(p + 0x0D));
+       printf("\tReal Mode 16-bit Data Address: %04X:0000\n",
+               WORD(p + 0x1B));
+       printf("\t16-bit Protected Mode Code Address: 0x%08X\n",
+               DWORD(p + 0x13) + WORD(p + 0x11));
+       printf("\t16-bit Protected Mode Data Address: 0x%08X\n",
+               DWORD(p + 0x1D));
+       if (DWORD(p + 0x17) != 0)
+               printf("\tOEM Device Identifier: %c%c%c%02X%02X\n",
+                       0x40 + ((p[0x17] >> 2) & 0x1F),
+                       0x40 + ((p[0x17] & 0x03) << 3) + ((p[0x18] >> 5) & 0x07),
+                       0x40 + (p[0x18] & 0x1F), p[0x19], p[0x20]);
+
+       return 1;
+}
+
+/*
+ * ACPI
+ */
+
+static size_t acpi_length(const u8 *p)
+{
+       return p[15] == 2 ? 36 : 20;
+}
+
+static const char *acpi_revision(u8 code)
+{
+       switch (code)
+       {
+               case 0:
+                       return " 1.0";
+               case 2:
+                       return " 2.0";
+               default:
+                       return "";
+       }
+}
+
+static int acpi_decode(const u8 *p, size_t len)
+{
+       if (len < 20 || !checksum(p, 20))
+               return 0;
+
+       printf("ACPI%s present.\n",
+               acpi_revision(p[15]));
+       printf("\tOEM Identifier: %c%c%c%c%c%c\n",
+               p[9], p[10], p[11], p[12], p[13], p[14]);
+       printf("\tRSD Table 32-bit Address: 0x%08X\n",
+               DWORD(p + 16));
+
+       if (len < 36)
+               return 1;
+
+       if (DWORD(p + 20) > len || !checksum(p, DWORD(p + 20)))
+               return 0;
+
+       if (DWORD(p + 20) < 32) return 1;
+
+       printf("\tXSD Table 64-bit Address: 0x%08X%08X\n",
+               QWORD(p + 24).h, QWORD(p + 24).l);
+
+       return 1;
+}
+
+/*
+ * Sony
+ */
+
+static size_t sony_length(const u8 *p)
+{
+       return p[0x05];
+}
+
+static int sony_decode(const u8 *p, size_t len)
+{
+       if (!checksum(p, len))
+               return 0;
+
+       printf("Sony system detected.\n");
+
+       return 1;
+}
+
+/*
+ * BIOS32
+ */
+
+static size_t bios32_length(const u8 *p)
+{
+       return p[0x09] << 4;
+}
+
+static int bios32_decode(const u8 *p, size_t len)
+{
+       if (len < 0x0A || !checksum(p, p[0x09] << 4))
+               return 0;
+
+       printf("BIOS32 Service Directory present.\n");
+       printf("\tRevision: %u\n",
+               p[0x08]);
+       printf("\tCalling Interface Address: 0x%08X\n",
+               DWORD(p + 0x04));
+
+       return 1;
+}
+
+/*
+ * PIR
+ */
+
+static void pir_irqs(u16 code)
+{
+       if (code == 0)
+               printf(" None");
+       else
+       {
+               u8 i;
+
+               for (i = 0; i < 16; i++)
+                       if (code & (1 << i))
+                               printf(" %u", i);
+       }
+}
+
+static void pir_slot_number(u8 code)
+{
+       if (code == 0)
+               printf(" on-board");
+       else
+               printf(" slot number %u", code);
+}
+
+static size_t pir_length(const u8 *p)
+{
+       return WORD(p + 6);
+}
+
+static int pir_decode(const u8 *p, size_t len)
+{
+       int i;
+
+       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",
+               p[8], p[9]>>3, p[9] & 0x07);
+       printf("\tExclusive IRQs:");
+       pir_irqs(WORD(p + 10));
+       printf("\n");
+       if (DWORD(p + 12) != 0)
+               printf("\tCompatible Router: %04x:%04x\n",
+                       WORD(p + 12), WORD(p + 14));
+       if (DWORD(p + 16) != 0)
+               printf("\tMiniport Data: 0x%08X\n",
+                       DWORD(p + 16));
+
+       for (i = 1; i <= (WORD(p + 6) - 32) / 16; i++)
+       {
+               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("\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");*/
+       }
+
+       return 1;
+}
+
+/*
+ * Compaq-specific entries
+ */
+
+static size_t compaq_length(const u8 *p)
+{
+       return p[4] * 10 + 5;
+}
+
+static int compaq_decode(const u8 *p, size_t len)
+{
+       unsigned int i;
+       (void) len;
+
+       printf("Compaq-specific entries present.\n");
+
+       /* integrity checking (lack of checksum) */
+       for (i = 0; i < p[4]; i++)
+       {
+               /*
+                * We do not check for truncated entries, because the length
+                * was computed from the number of records in compaq_length
+                * right above, so it can't be wrong.
+                */
+               if (p[5 + i * 10] != '$'
+                || !(p[6 + i * 10] >= 'A' && p[6 + i * 10] <= 'Z')
+                || !(p[7 + i * 10] >= 'A' && p[7 + i * 10] <= 'Z')
+                || !(p[8 + i * 10] >= 'A' && p[8 + i * 10] <= 'Z'))
+               {
+                       printf("\t Abnormal entry! Please report. [%02X %02X "
+                               "%02X %02X]\n", p[5 + i * 10], p[6 + i * 10],
+                               p[7 + i * 10], p[8 + i * 10]);
+                       return 0;
+               }
+       }
+
+       for (i = 0; i < p[4]; i++)
+       {
+               printf("\tEntry %u: %c%c%c%c at 0x%08X (%u bytes)\n",
+                       i + 1, p[5 + i * 10], p[6 + i * 10], p[7 + i * 10],
+                       p[8 + i * 10], DWORD(p + 9 + i * 10),
+                       WORD(p + 13 + i * 10));
+       }
+
+       return 1;
+}
+
+/*
+ * VPD (vital product data, IBM-specific)
+ */
+
+static void vpd_print_entry(const char *name, const u8 *p, size_t len)
+{
+       size_t i;
+
+       printf("\t%s: ", name);
+       for (i = 0; i < len; i++)
+               if (p[i] >= 32 && p[i] < 127)
+                       printf("%c", p[i]);
+       printf("\n");
+}
+
+static size_t vpd_length(const u8 *p)
+{
+       return p[5];
+}
+
+static int vpd_decode(const u8 *p, size_t len)
+{
+       if (len < 0x30)
+               return 0;
+
+       /* XSeries have longer records. */
+       if (!(len >= 0x45 && checksum(p, len))
+       /* Some Netvista seem to work with this. */
+        && !checksum(p, 0x30)
+       /* The Thinkpad checksum does *not* include the first 13 bytes. */
+        && !checksum(p + 0x0D, 0x30 - 0x0D))
+               return 0;
+
+       printf("VPD present.\n");
+
+       vpd_print_entry("BIOS Build ID", p + 0x0D, 9);
+       vpd_print_entry("Box Serial Number", p + 0x16, 7);
+       vpd_print_entry("Motherboard Serial Number", p + 0x1D, 11);
+       vpd_print_entry("Machine Type/Model", p + 0x28, 7);
+
+       if (len < 0x45)
+               return 1;
+
+       vpd_print_entry("BIOS Release Date", p + 0x30, 8);
+
+       return 1;
+}
+
+/*
+ * Fujitsu application panel
+ */
+
+static size_t fjkeyinf_length(const u8 *p)
+{
+       (void) p;
+       /*
+        * We don't know at this point, it's somewhere between 12 and 32.
+        * So we return the max, it shouldn't hurt.
+        */
+       return 32;
+}
+
+static int fjkeyinf_decode(const u8 *p, size_t len)
+{
+       int i;
+       (void) len;
+
+       printf("Fujitsu application panel present.\n");
+
+       for (i = 0; i < 6; i++)
+       {
+               if (*(p + 8 + i * 4) == 0)
+                       return 1;
+               printf("\tDevice %d: type %u, chip %u", i + 1,
+                      *(p + 8 + i * 4), *(p + 8 + i * 4 + 2));
+               if (*(p+8+i*4+1)) /* Access method */
+                       printf(", SMBus address 0x%x",
+                               *(p + 8 + i * 4 + 3) >> 1);
+               printf("\n");
+       }
+
+       return 1;
+}
+
+/*
+ * Main
+ */
+
+static struct bios_entry bios_entries[] = {
+       { "_SM_", 0, 0xF0000, 0xFFFFF, smbios_length, smbios_decode },
+       { "_DMI_", 0, 0xF0000, 0xFFFFF, dmi_length, dmi_decode },
+       { "_SYSID_", 0, 0xE0000, 0xFFFFF, sysid_length, sysid_decode },
+       { "$PnP", 0, 0xF0000, 0xFFFFF, pnp_length, pnp_decode },
+       { "RSD PTR ", 0, 0xE0000, 0xFFFFF, acpi_length, acpi_decode },
+       { "$SNY", 0, 0xE0000, 0xFFFFF, sony_length, sony_decode },
+       { "_32_", 0, 0xE0000, 0xFFFFF, bios32_length, bios32_decode },
+       { "$PIR", 0, 0xF0000, 0xFFFFF, pir_length, pir_decode },
+       { "32OS", 0, 0xE0000, 0xFFFFF, compaq_length, compaq_decode },
+       { "\252\125VPD", 0, 0xF0000, 0xFFFFF, vpd_length, vpd_decode },
+       { "FJKEYINF", 0, 0xF0000, 0xFFFFF, fjkeyinf_length, fjkeyinf_decode },
+       { NULL, 0, 0, 0, NULL, NULL }
+};
+
+/* Believe it or not, this is significantly faster than memcmp */
+static int anchor_match(const struct bios_entry *entry, const char *p)
+{
+       size_t i;
+
+       for (i = 0; i < entry->anchor_len; i++)
+               if (entry->anchor[i] != p[i])
+                       return 0;
+
+       return 1;
+}
+
+/* Return -1 on error, 0 on success */
+static int parse_command_line(int argc, char * const argv[])
+{
+       int option;
+       const char *optstring = "d:hV";
+       struct option longopts[] = {
+               { "dev-mem", required_argument, NULL, 'd' },
+               { "help", no_argument, NULL, 'h' },
+               { "version", no_argument, NULL, 'V' },
+               { 0, 0, 0, 0 }
+       };
+
+       while ((option = getopt_long(argc, argv, optstring, longopts, NULL)) != -1)
+               switch (option)
+               {
+                       case 'd':
+                               opt.devmem = optarg;
+                               break;
+                       case 'h':
+                               opt.flags |= FLAG_HELP;
+                               break;
+                       case 'V':
+                               opt.flags |= FLAG_VERSION;
+                               break;
+                       case '?':
+                               return -1;
+               }
+
+       return 0;
+}
+
+static void print_help(void)
+{
+       static const char *help =
+               "Usage: biosdecode [OPTIONS]\n"
+               "Options are:\n"
+               " -d, --dev-mem FILE     Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n"
+               " -h, --help             Display this help text and exit\n"
+               " -V, --version          Display the version and exit\n";
+
+       printf("%s", help);
+}
+
+int main(int argc, char * const argv[])
+{
+       u8 *buf;
+       off_t fp;
+       int i;
+
+       if (sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4)
+       {
+               fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
+               exit(255);
+       }
+
+       /* Set default option values */
+       opt.devmem = DEFAULT_MEM_DEV;
+       opt.flags = 0;
+
+       if (parse_command_line(argc, argv) < 0)
+               exit(2);
+
+       if (opt.flags & FLAG_HELP)
+       {
+               print_help();
+               return 0;
+       }
+
+       if (opt.flags & FLAG_VERSION)
+       {
+               printf("%s\n", VERSION);
+               return 0;
+       }
+
+       printf("# biosdecode %s\n", VERSION);
+
+       if ((buf = mem_chunk(0xE0000, 0x20000, opt.devmem)) == NULL)
+               exit(1);
+
+       /* Compute anchor lengths once and for all */
+       for (i = 0; bios_entries[i].anchor != NULL; i++)
+               bios_entries[i].anchor_len = strlen(bios_entries[i].anchor);
+
+       for (fp = 0xE0000; fp <= 0xFFFF0; fp += 16)
+       {
+               u8 *p = buf + fp - 0xE0000;
+
+               for (i = 0; bios_entries[i].anchor != NULL; i++)
+               {
+                       if (anchor_match(&bios_entries[i], (char *)p)
+                        && fp >= bios_entries[i].low_address
+                        && fp < bios_entries[i].high_address)
+                       {
+                               off_t len = bios_entries[i].length(p);
+
+                               if (fp + len - 1 <= bios_entries[i].high_address)
+                               {
+                                       if (bios_entries[i].decode(p, len))
+                                       {
+                                               fp += (((len - 1) >> 4) << 4);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       free(buf);
+
+       return 0;
+}
diff --git a/config.h b/config.h
new file mode 100644 (file)
index 0000000..52fd3c3
--- /dev/null
+++ b/config.h
@@ -0,0 +1,29 @@
+/*
+ * Configuration
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* Default memory device file */
+#ifdef __BEOS__
+#define DEFAULT_MEM_DEV "/dev/misc/mem"
+#else
+#ifdef __sun
+#define DEFAULT_MEM_DEV "/dev/xsvc"
+#else
+#define DEFAULT_MEM_DEV "/dev/mem"
+#endif
+#endif
+
+/* Use mmap or not */
+#ifndef __BEOS__
+#define USE_MMAP
+#endif
+
+/* Use memory alignment workaround or not */
+#ifdef __ia64__
+#define ALIGNMENT_WORKAROUND
+#endif
+
+#endif
diff --git a/dmidecode.c b/dmidecode.c
new file mode 100644 (file)
index 0000000..5c7ad0e
--- /dev/null
@@ -0,0 +1,4648 @@
+/*
+ * DMI Decode
+ *
+ *   Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
+ *   Copyright (C) 2002-2010 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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
+ *
+ *   For the avoidance of doubt the "preferred form" of this code is one which
+ *   is in an open unpatent encumbered format. Where cryptographic key signing
+ *   forms part of the process of creating an executable the information
+ *   including keys needed to generate an equivalently functional executable
+ *   are deemed to be part of the source code.
+ *
+ * Unless specified otherwise, all references are aimed at the "System
+ * Management BIOS Reference Specification, Version 2.7.0" document,
+ * available from http://www.dmtf.org/standards/smbios.
+ *
+ * Note to contributors:
+ * Please reference every value you add or modify, especially if the
+ * information does not come from the above mentioned specification.
+ *
+ * Additional references:
+ *  - Intel AP-485 revision 36
+ *    "Intel Processor Identification and the CPUID Instruction"
+ *    http://www.intel.com/support/processors/sb/cs-009861.htm
+ *  - DMTF Common Information Model
+ *    CIM Schema version 2.19.1
+ *    http://www.dmtf.org/standards/cim/
+ *  - IPMI 2.0 revision 1.0
+ *    "Intelligent Platform Management Interface Specification"
+ *    http://developer.intel.com/design/servers/ipmi/spec.htm
+ *  - AMD publication #25481 revision 2.28
+ *    "CPUID Specification"
+ *    http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf
+ *  - BIOS Integrity Services Application Programming Interface version 1.0
+ *    http://www.intel.com/design/archives/wfm/downloads/bisspec.htm
+ *  - DMTF DSP0239 version 1.1.0
+ *    "Management Component Transport Protocol (MCTP) IDs and Codes"
+ *    http://www.dmtf.org/standards/pmci
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "version.h"
+#include "config.h"
+#include "types.h"
+#include "util.h"
+#include "dmidecode.h"
+#include "dmiopt.h"
+#include "dmioem.h"
+
+#define out_of_spec "<OUT OF SPEC>"
+static const char *bad_index = "<BAD INDEX>";
+
+#define SUPPORTED_SMBIOS_VER 0x0207
+
+/*
+ * Type-independant Stuff
+ */
+
+const char *dmi_string(const struct dmi_header *dm, u8 s)
+{
+       char *bp = (char *)dm->data;
+       size_t i, len;
+
+       if (s == 0)
+               return "Not Specified";
+
+       bp += dm->length;
+       while (s > 1 && *bp)
+       {
+               bp += strlen(bp);
+               bp++;
+               s--;
+       }
+
+       if (!*bp)
+               return bad_index;
+
+       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] = '.';
+       }
+
+       return bp;
+}
+
+static const char *dmi_smbios_structure_type(u8 code)
+{
+       static const char *type[] = {
+               "BIOS", /* 0 */
+               "System",
+               "Base Board",
+               "Chassis",
+               "Processor",
+               "Memory Controller",
+               "Memory Module",
+               "Cache",
+               "Port Connector",
+               "System Slots",
+               "On Board Devices",
+               "OEM Strings",
+               "System Configuration Options",
+               "BIOS Language",
+               "Group Associations",
+               "System Event Log",
+               "Physical Memory Array",
+               "Memory Device",
+               "32-bit Memory Error",
+               "Memory Array Mapped Address",
+               "Memory Device Mapped Address",
+               "Built-in Pointing Device",
+               "Portable Battery",
+               "System Reset",
+               "Hardware Security",
+               "System Power Controls",
+               "Voltage Probe",
+               "Cooling Device",
+               "Temperature Probe",
+               "Electrical Current Probe",
+               "Out-of-band Remote Access",
+               "Boot Integrity Services",
+               "System Boot",
+               "64-bit Memory Error",
+               "Management Device",
+               "Management Device Component",
+               "Management Device Threshold Data",
+               "Memory Channel",
+               "IPMI Device",
+               "Power Supply",
+               "Additional Information",
+               "Onboard Device",
+               "Management Controller Host Interface", /* 42 */
+       };
+
+       if (code <= 42)
+               return type[code];
+       return out_of_spec;
+}
+
+static int dmi_bcd_range(u8 value, u8 low, u8 high)
+{
+       if (value > 0x99 || (value & 0x0F) > 0x09)
+               return 0;
+       if (value < low || value > high)
+               return 0;
+       return 1;
+}
+
+static void dmi_dump(const struct dmi_header *h, const char *prefix)
+{
+       int row, i;
+       const char *s;
+
+       printf("%sHeader and Data:\n", prefix);
+       for (row = 0; row < ((h->length - 1) >> 4) + 1; row++)
+       {
+               printf("%s\t", prefix);
+               for (i = 0; i < 16 && i < h->length - (row << 4); i++)
+                       printf("%s%02X", i ? " " : "",
+                              (h->data)[(row << 4) + i]);
+               printf("\n");
+       }
+
+       if ((h->data)[h->length] || (h->data)[h->length + 1])
+       {
+               printf("%sStrings:\n", prefix);
+               i = 1;
+               while ((s = dmi_string(h, i++)) != bad_index)
+               {
+                       if (opt.flags & FLAG_DUMP)
+                       {
+                               int j, l = strlen(s) + 1;
+                               for (row = 0; row < ((l - 1) >> 4) + 1; row++)
+                               {
+                                       printf("%s\t", prefix);
+                                       for (j = 0; j < 16 && j < l - (row << 4); j++)
+                                               printf("%s%02X", j ? " " : "",
+                                                      s[(row << 4) + j]);
+                                       printf("\n");
+                               }
+                               /* 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");
+                       }
+                       else
+                               printf("%s\t%s\n", prefix, s);
+               }
+       }
+}
+
+/* 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)
+{
+       unsigned long capacity;
+       u16 split[7];
+       static const char *unit[8] = {
+               "bytes", "kB", "MB", "GB", "TB", "PB", "EB", "ZB"
+       };
+       int i;
+
+       /*
+        * We split the overall size in powers of thousand: EB, PB, TB, GB,
+        * MB, kB and B. In practice, it is expected that only one or two
+        * (consecutive) of these will be non-zero.
+        */
+       split[0] = code.l & 0x3FFUL;
+       split[1] = (code.l >> 10) & 0x3FFUL;
+       split[2] = (code.l >> 20) & 0x3FFUL;
+       split[3] = ((code.h << 2) & 0x3FCUL) | (code.l >> 30);
+       split[4] = (code.h >> 8) & 0x3FFUL;
+       split[5] = (code.h >> 18) & 0x3FFUL;
+       split[6] = code.h >> 28;
+
+       /*
+        * Now we find the highest unit with a non-zero value. If the following
+        * is also non-zero, we use that as our base. If the following is zero,
+        * we simply display the highest unit.
+        */
+       for (i = 6; i > 0; i--)
+       {
+               if (split[i])
+                       break;
+       }
+       if (i > 0 && split[i - 1])
+       {
+               i--;
+               capacity = split[i] + (split[i + 1] << 10);
+       }
+       else
+               capacity = split[i];
+
+       printf(" %lu %s", capacity, unit[i + shift]);
+}
+
+/*
+ * 7.1 BIOS Information (Type 0)
+ */
+
+static void dmi_bios_runtime_size(u32 code)
+{
+       if (code & 0x000003FF)
+               printf(" %u bytes", code);
+       else
+               printf(" %u kB", code >> 10);
+}
+
+static void dmi_bios_characteristics(u64 code, const char *prefix)
+{
+       /* 7.1.1 */
+       static const char *characteristics[] = {
+               "BIOS characteristics not supported", /* 3 */
+               "ISA is supported",
+               "MCA is supported",
+               "EISA is supported",
+               "PCI is supported",
+               "PC Card (PCMCIA) is supported",
+               "PNP is supported",
+               "APM is supported",
+               "BIOS is upgradeable",
+               "BIOS shadowing is allowed",
+               "VLB is supported",
+               "ESCD support is available",
+               "Boot from CD is supported",
+               "Selectable boot is supported",
+               "BIOS ROM is socketed",
+               "Boot from PC Card (PCMCIA) is supported",
+               "EDD is supported",
+               "Japanese floppy for NEC 9800 1.2 MB is supported (int 13h)",
+               "Japanese floppy for Toshiba 1.2 MB is supported (int 13h)",
+               "5.25\"/360 kB floppy services are supported (int 13h)",
+               "5.25\"/1.2 MB floppy services are supported (int 13h)",
+               "3.5\"/720 kB floppy services are supported (int 13h)",
+               "3.5\"/2.88 MB floppy services are supported (int 13h)",
+               "Print screen service is supported (int 5h)",
+               "8042 keyboard services are supported (int 9h)",
+               "Serial services are supported (int 14h)",
+               "Printer services are supported (int 17h)",
+               "CGA/mono video services are supported (int 10h)",
+               "NEC PC-98" /* 31 */
+       };
+       int i;
+
+       /*
+        * This isn't very clear what this bit is supposed to mean
+        */
+       if (code.l & (1 << 3))
+       {
+               printf("%s%s\n",
+                       prefix, characteristics[0]);
+               return;
+       }
+
+       for (i = 4; i <= 31; i++)
+               if (code.l & (1 << i))
+                       printf("%s%s\n",
+                               prefix, characteristics[i - 3]);
+}
+
+static void dmi_bios_characteristics_x1(u8 code, const char *prefix)
+{
+       /* 7.1.2.1 */
+       static const char *characteristics[] = {
+               "ACPI is supported", /* 0 */
+               "USB legacy is supported",
+               "AGP is supported",
+               "I2O boot is supported",
+               "LS-120 boot is supported",
+               "ATAPI Zip drive boot is supported",
+               "IEEE 1394 boot is supported",
+               "Smart battery is supported" /* 7 */
+       };
+       int i;
+
+       for (i = 0; i <= 7; i++)
+               if (code & (1 << i))
+                       printf("%s%s\n",
+                               prefix, characteristics[i]);
+}
+
+static void dmi_bios_characteristics_x2(u8 code, const char *prefix)
+{
+       /* 37.1.2.2 */
+       static const char *characteristics[] = {
+               "BIOS boot specification is supported", /* 0 */
+               "Function key-initiated network boot is supported",
+               "Targeted content distribution is supported",
+               "UEFI is supported",
+               "System is a virtual machine" /* 4 */
+       };
+       int i;
+
+       for (i = 0; i <= 4; i++)
+               if (code & (1 << i))
+                       printf("%s%s\n",
+                               prefix, characteristics[i]);
+}
+
+/*
+ * 7.2 System Information (Type 1)
+ */
+
+static void dmi_system_uuid(const u8 *p, u16 ver)
+{
+       int only0xFF = 1, only0x00 = 1;
+       int i;
+
+       for (i = 0; i < 16 && (only0x00 || only0xFF); i++)
+       {
+               if (p[i] != 0x00) only0x00 = 0;
+               if (p[i] != 0xFF) only0xFF = 0;
+       }
+
+       if (only0xFF)
+       {
+               printf("Not Present");
+               return;
+       }
+       if (only0x00)
+       {
+               printf("Not Settable");
+               return;
+       }
+
+       /*
+        * As of version 2.6 of the SMBIOS specification, the first 3
+        * fields of the UUID are supposed to be encoded on little-endian.
+        * The specification says that this is the defacto standard,
+        * however I've seen systems following RFC 4122 instead and use
+        * network byte order, so I am reluctant to apply the byte-swapping
+        * 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]);
+       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]);
+}
+
+static const char *dmi_system_wake_up_type(u8 code)
+{
+       /* 7.2.2 */
+       static const char *type[] = {
+               "Reserved", /* 0x00 */
+               "Other",
+               "Unknown",
+               "APM Timer",
+               "Modem Ring",
+               "LAN Remote",
+               "Power Switch",
+               "PCI PME#",
+               "AC Power Restored" /* 0x08 */
+       };
+
+       if (code <= 0x08)
+               return type[code];
+       return out_of_spec;
+}
+
+/*
+ * 7.3 Base Board Information (Type 2)
+ */
+
+static void dmi_base_board_features(u8 code, const char *prefix)
+{
+       /* 7.3.1 */
+       static const char *features[] = {
+               "Board is a hosting board", /* 0 */
+               "Board requires at least one daughter board",
+               "Board is removable",
+               "Board is replaceable",
+               "Board is hot swappable" /* 4 */
+       };
+
+       if ((code & 0x1F) == 0)
+               printf(" None\n");
+       else
+       {
+               int i;
+
+               printf("\n");
+               for (i = 0; i <= 4; i++)
+                       if (code & (1 << i))
+                               printf("%s%s\n",
+                                       prefix, features[i]);
+       }
+}
+
+static const char *dmi_base_board_type(u8 code)
+{
+       /* 7.3.2 */
+       static const char *type[] = {
+               "Unknown", /* 0x01 */
+               "Other",
+               "Server Blade",
+               "Connectivity Switch",
+               "System Management Module",
+               "Processor Module",
+               "I/O Module",
+               "Memory Module",
+               "Daughter Board",
+               "Motherboard",
+               "Processor+Memory Module",
+               "Processor+I/O Module",
+               "Interconnect Board" /* 0x0D */
+       };
+
+       if (code >= 0x01 && code <= 0x0D)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_base_board_handles(u8 count, const u8 *p, const char *prefix)
+{
+       int i;
+
+       printf("%sContained Object Handles: %u\n",
+               prefix, count);
+       for (i = 0; i < count; i++)
+               printf("%s\t0x%04X\n",
+                       prefix, WORD(p + sizeof(u16) * i));
+}
+
+/*
+ * 7.4 Chassis Information (Type 3)
+ */
+
+static const char *dmi_chassis_type(u8 code)
+{
+       /* 7.4.1 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Desktop",
+               "Low Profile Desktop",
+               "Pizza Box",
+               "Mini Tower",
+               "Tower",
+               "Portable",
+               "Laptop",
+               "Notebook",
+               "Hand Held",
+               "Docking Station",
+               "All In One",
+               "Sub Notebook",
+               "Space-saving",
+               "Lunch Box",
+               "Main Server Chassis", /* CIM_Chassis.ChassisPackageType says "Main System Chassis" */
+               "Expansion Chassis",
+               "Sub Chassis",
+               "Bus Expansion Chassis",
+               "Peripheral Chassis",
+               "RAID Chassis",
+               "Rack Mount Chassis",
+               "Sealed-case PC",
+               "Multi-system",
+               "CompactPCI",
+               "AdvancedTCA",
+               "Blade",
+               "Blade Enclosing" /* 0x1D */
+       };
+
+       if (code >= 0x01 && code <= 0x1D)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_chassis_lock(u8 code)
+{
+       static const char *lock[] = {
+               "Not Present", /* 0x00 */
+               "Present" /* 0x01 */
+       };
+
+       return lock[code];
+}
+
+static const char *dmi_chassis_state(u8 code)
+{
+       /* 7.4.2 */
+       static const char *state[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Safe",
+               "Warning",
+               "Critical",
+               "Non-recoverable" /* 0x06 */
+       };
+
+       if (code >= 0x01 && code <= 0x06)
+               return state[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_chassis_security_status(u8 code)
+{
+       /* 7.4.3 */
+       static const char *status[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "None",
+               "External Interface Locked Out",
+               "External Interface Enabled" /* 0x05 */
+       };
+
+       if (code >= 0x01 && code <= 0x05)
+               return status[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_chassis_height(u8 code)
+{
+       if (code == 0x00)
+               printf(" Unspecified");
+       else
+               printf(" %u U", code);
+}
+
+static void dmi_chassis_power_cords(u8 code)
+{
+       if (code == 0x00)
+               printf(" Unspecified");
+       else
+               printf(" %u", code);
+}
+
+static void dmi_chassis_elements(u8 count, u8 len, const u8 *p, const char *prefix)
+{
+       int i;
+
+       printf("%sContained Elements: %u\n",
+               prefix, count);
+       for (i = 0; i < count; i++)
+       {
+               if (len >= 0x03)
+               {
+                       printf("%s\t%s (",
+                               prefix, p[i * len] & 0x80 ?
+                               dmi_smbios_structure_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]);
+                       else
+                               printf("%u-%u", p[1 + i * len], p[2 + i * len]);
+                       printf(")\n");
+               }
+       }
+}
+
+/*
+ * 7.5 Processor Information (Type 4)
+ */
+
+static const char *dmi_processor_type(u8 code)
+{
+       /* 7.5.1 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Central Processor",
+               "Math Processor",
+               "DSP Processor",
+               "Video Processor" /* 0x06 */
+       };
+
+       if (code >= 0x01 && code <= 0x06)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
+{
+       const u8 *data = h->data;
+       unsigned int i, low, high;
+       u16 code;
+
+       /* 7.5.2 */
+       static struct {
+               int value;
+               const char *name;
+       } family2[] = {
+               { 0x01, "Other" },
+               { 0x02, "Unknown" },
+               { 0x03, "8086" },
+               { 0x04, "80286" },
+               { 0x05, "80386" },
+               { 0x06, "80486" },
+               { 0x07, "8087" },
+               { 0x08, "80287" },
+               { 0x09, "80387" },
+               { 0x0A, "80487" },
+               { 0x0B, "Pentium" },
+               { 0x0C, "Pentium Pro" },
+               { 0x0D, "Pentium II" },
+               { 0x0E, "Pentium MMX" },
+               { 0x0F, "Celeron" },
+               { 0x10, "Pentium II Xeon" },
+               { 0x11, "Pentium III" },
+               { 0x12, "M1" },
+               { 0x13, "M2" },
+               { 0x14, "Celeron M" },
+               { 0x15, "Pentium 4 HT" },
+
+               { 0x18, "Duron" },
+               { 0x19, "K5" },
+               { 0x1A, "K6" },
+               { 0x1B, "K6-2" },
+               { 0x1C, "K6-3" },
+               { 0x1D, "Athlon" },
+               { 0x1E, "AMD29000" },
+               { 0x1F, "K6-2+" },
+               { 0x20, "Power PC" },
+               { 0x21, "Power PC 601" },
+               { 0x22, "Power PC 603" },
+               { 0x23, "Power PC 603+" },
+               { 0x24, "Power PC 604" },
+               { 0x25, "Power PC 620" },
+               { 0x26, "Power PC x704" },
+               { 0x27, "Power PC 750" },
+               { 0x28, "Core Duo" },
+               { 0x29, "Core Duo Mobile" },
+               { 0x2A, "Core Solo Mobile" },
+               { 0x2B, "Atom" },
+
+               { 0x30, "Alpha" },
+               { 0x31, "Alpha 21064" },
+               { 0x32, "Alpha 21066" },
+               { 0x33, "Alpha 21164" },
+               { 0x34, "Alpha 21164PC" },
+               { 0x35, "Alpha 21164a" },
+               { 0x36, "Alpha 21264" },
+               { 0x37, "Alpha 21364" },
+               { 0x38, "Turion II Ultra Dual-Core Mobile M" },
+               { 0x39, "Turion II Dual-Core Mobile M" },
+               { 0x3A, "Athlon II Dual-Core M" },
+               { 0x3B, "Opteron 6100" },
+               { 0x3C, "Opteron 4100" },
+
+               { 0x40, "MIPS" },
+               { 0x41, "MIPS R4000" },
+               { 0x42, "MIPS R4200" },
+               { 0x43, "MIPS R4400" },
+               { 0x44, "MIPS R4600" },
+               { 0x45, "MIPS R10000" },
+
+               { 0x50, "SPARC" },
+               { 0x51, "SuperSPARC" },
+               { 0x52, "MicroSPARC II" },
+               { 0x53, "MicroSPARC IIep" },
+               { 0x54, "UltraSPARC" },
+               { 0x55, "UltraSPARC II" },
+               { 0x56, "UltraSPARC IIi" },
+               { 0x57, "UltraSPARC III" },
+               { 0x58, "UltraSPARC IIIi" },
+
+               { 0x60, "68040" },
+               { 0x61, "68xxx" },
+               { 0x62, "68000" },
+               { 0x63, "68010" },
+               { 0x64, "68020" },
+               { 0x65, "68030" },
+
+               { 0x70, "Hobbit" },
+
+               { 0x78, "Crusoe TM5000" },
+               { 0x79, "Crusoe TM3000" },
+               { 0x7A, "Efficeon TM8000" },
+
+               { 0x80, "Weitek" },
+
+               { 0x82, "Itanium" },
+               { 0x83, "Athlon 64" },
+               { 0x84, "Opteron" },
+               { 0x85, "Sempron" },
+               { 0x86, "Turion 64" },
+               { 0x87, "Dual-Core Opteron" },
+               { 0x88, "Athlon 64 X2" },
+               { 0x89, "Turion 64 X2" },
+               { 0x8A, "Quad-Core Opteron" },
+               { 0x8B, "Third-Generation Opteron" },
+               { 0x8C, "Phenom FX" },
+               { 0x8D, "Phenom X4" },
+               { 0x8E, "Phenom X2" },
+               { 0x8F, "Athlon X2" },
+               { 0x90, "PA-RISC" },
+               { 0x91, "PA-RISC 8500" },
+               { 0x92, "PA-RISC 8000" },
+               { 0x93, "PA-RISC 7300LC" },
+               { 0x94, "PA-RISC 7200" },
+               { 0x95, "PA-RISC 7100LC" },
+               { 0x96, "PA-RISC 7100" },
+
+               { 0xA0, "V30" },
+               { 0xA1, "Quad-Core Xeon 3200" },
+               { 0xA2, "Dual-Core Xeon 3000" },
+               { 0xA3, "Quad-Core Xeon 5300" },
+               { 0xA4, "Dual-Core Xeon 5100" },
+               { 0xA5, "Dual-Core Xeon 5000" },
+               { 0xA6, "Dual-Core Xeon LV" },
+               { 0xA7, "Dual-Core Xeon ULV" },
+               { 0xA8, "Dual-Core Xeon 7100" },
+               { 0xA9, "Quad-Core Xeon 5400" },
+               { 0xAA, "Quad-Core Xeon" },
+               { 0xAB, "Dual-Core Xeon 5200" },
+               { 0xAC, "Dual-Core Xeon 7200" },
+               { 0xAD, "Quad-Core Xeon 7300" },
+               { 0xAE, "Quad-Core Xeon 7400" },
+               { 0xAF, "Multi-Core Xeon 7400" },
+               { 0xB0, "Pentium III Xeon" },
+               { 0xB1, "Pentium III Speedstep" },
+               { 0xB2, "Pentium 4" },
+               { 0xB3, "Xeon" },
+               { 0xB4, "AS400" },
+               { 0xB5, "Xeon MP" },
+               { 0xB6, "Athlon XP" },
+               { 0xB7, "Athlon MP" },
+               { 0xB8, "Itanium 2" },
+               { 0xB9, "Pentium M" },
+               { 0xBA, "Celeron D" },
+               { 0xBB, "Pentium D" },
+               { 0xBC, "Pentium EE" },
+               { 0xBD, "Core Solo" },
+               /* 0xBE handled as a special case */
+               { 0xBF, "Core 2 Duo" },
+               { 0xC0, "Core 2 Solo" },
+               { 0xC1, "Core 2 Extreme" },
+               { 0xC2, "Core 2 Quad" },
+               { 0xC3, "Core 2 Extreme Mobile" },
+               { 0xC4, "Core 2 Duo Mobile" },
+               { 0xC5, "Core 2 Solo Mobile" },
+               { 0xC6, "Core i7" },
+               { 0xC7, "Dual-Core Celeron" },
+               { 0xC8, "IBM390" },
+               { 0xC9, "G4" },
+               { 0xCA, "G5" },
+               { 0xCB, "ESA/390 G6" },
+               { 0xCC, "z/Architectur" },
+               { 0xCD, "Core i5" },
+               { 0xCE, "Core i3" },
+
+               { 0xD2, "C7-M" },
+               { 0xD3, "C7-D" },
+               { 0xD4, "C7" },
+               { 0xD5, "Eden" },
+               { 0xD6, "Multi-Core Xeon" },
+               { 0xD7, "Dual-Core Xeon 3xxx" },
+               { 0xD8, "Quad-Core Xeon 3xxx" },
+               { 0xD9, "Nano" },
+               { 0xDA, "Dual-Core Xeon 5xxx" },
+               { 0xDB, "Quad-Core Xeon 5xxx" },
+
+               { 0xDD, "Dual-Core Xeon 7xxx" },
+               { 0xDE, "Quad-Core Xeon 7xxx" },
+               { 0xDF, "Multi-Core Xeon 7xxx" },
+               { 0xE0, "Multi-Core Xeon 3400" },
+
+               { 0xE6, "Embedded Opteron Quad-Core" },
+               { 0xE7, "Phenom Triple-Core" },
+               { 0xE8, "Turion Ultra Dual-Core Mobile" },
+               { 0xE9, "Turion Dual-Core Mobile" },
+               { 0xEA, "Athlon Dual-Core" },
+               { 0xEB, "Sempron SI" },
+               { 0xEC, "Phenom II" },
+               { 0xED, "Athlon II" },
+               { 0xEE, "Six-Core Opteron" },
+               { 0xEF, "Sempron M" },
+
+               { 0xFA, "i860" },
+               { 0xFB, "i960" },
+
+               { 0x104, "SH-3" },
+               { 0x105, "SH-4" },
+               { 0x118, "ARM" },
+               { 0x119, "StrongARM" },
+               { 0x12C, "6x86" },
+               { 0x12D, "MediaGX" },
+               { 0x12E, "MII" },
+               { 0x140, "WinChip" },
+               { 0x15E, "DSP" },
+               { 0x1F4, "Video Processor" },
+       };
+
+       /* Special case for ambiguous value 0x30 (SMBIOS 2.0 only) */
+       if (ver == 0x0200 && data[0x06] == 0x30 && h->length >= 0x08)
+       {
+               const char *manufacturer = dmi_string(h, data[0x07]);
+
+               if (strstr(manufacturer, "Intel") != NULL
+                || strncasecmp(manufacturer, "Intel", 5) == 0)
+                       return "Pentium Pro";
+       }
+
+       code = (data[0x06] == 0xFE && h->length >= 0x2A) ?
+               WORD(data + 0x28) : data[0x06];
+
+       /* Special case for ambiguous value 0xBE */
+       if (code == 0xBE)
+       {
+               if (h->length >= 0x08)
+               {
+                       const char *manufacturer = dmi_string(h, data[0x07]);
+
+                       /* Best bet based on manufacturer string */
+                       if (strstr(manufacturer, "Intel") != NULL
+                        || strncasecmp(manufacturer, "Intel", 5) == 0)
+                               return "Core 2";
+                       if (strstr(manufacturer, "AMD") != NULL
+                        || strncasecmp(manufacturer, "AMD", 3) == 0)
+                               return "K7";
+               }
+
+               return "Core 2 or K7";
+       }
+
+       /* Perform a binary search */
+       low = 0;
+       high = ARRAY_SIZE(family2) - 1;
+
+       while (1)
+       {
+               i = (low + high) / 2;
+               if (family2[i].value == code)
+                       return family2[i].name;
+               if (low == high) /* Not found */
+                       return out_of_spec;
+
+               if (code < family2[i].value)
+                       high = i;
+               else
+                       low = i + 1;
+       }
+}
+
+static void dmi_processor_id(u8 type, const u8 *p, const char *version, const char *prefix)
+{
+       /* 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 */
+       };
+       /*
+        * 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.
+        */
+       u32 eax, edx;
+       int sig = 0;
+
+       /*
+        * 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;
+       }
+       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
+                * 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;
+               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;
+               }
+       }
+       else if ((type >= 0x0B && type <= 0x15) /* Intel, Cyrix */
+             || (type >= 0x28 && type <= 0x2B) /* Intel */
+             || (type >= 0xA1 && type <= 0xB3) /* Intel */
+             || type == 0xB5 /* Intel */
+             || (type >= 0xB9 && type <= 0xC7) /* Intel */
+             || (type >= 0xCD && type <= 0xCE) /* Intel */
+             || (type >= 0xD2 && type <= 0xDB) /* VIA, Intel */
+             || (type >= 0xDD && type <= 0xE0)) /* Intel */
+               sig = 1;
+       else if ((type >= 0x18 && type <= 0x1D) /* AMD */
+             || type == 0x1F /* AMD */
+             || (type >= 0x38 && type <= 0x3C) /* AMD */
+             || (type >= 0x83 && type <= 0x8F) /* AMD */
+             || (type >= 0xB6 && type <= 0xB7) /* AMD */
+             || (type >= 0xE6 && type <= 0xEF)) /* AMD */
+               sig = 2;
+       else if (type == 0x01 || type == 0x02)
+       {
+               /*
+                * 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 /* not X86-class */
+               return;
+
+       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);
+                       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);
+                       break;
+       }
+
+       edx = DWORD(p + 4);
+       printf("%sFlags:", prefix);
+       if ((edx & 0xBFEFFBFF) == 0)
+               printf(" None\n");
+       else
+       {
+               int i;
+
+               printf("\n");
+               for (i = 0; i <= 31; i++)
+                       if (flags[i] != NULL && edx & (1 << i))
+                               printf("%s\t%s\n", prefix, flags[i]);
+       }
+}
+
+static void dmi_processor_voltage(u8 code)
+{
+       /* 7.5.4 */
+       static const char *voltage[] = {
+               "5.0 V", /* 0 */
+               "3.3 V",
+               "2.9 V" /* 2 */
+       };
+       int i;
+
+       if (code & 0x80)
+               printf(" %.1f V", (float)(code & 0x7f) / 10);
+       else
+       {
+               for (i = 0; i <= 2; i++)
+                       if (code & (1 << i))
+                               printf(" %s", voltage[i]);
+               if (code == 0x00)
+                       printf(" Unknown");
+       }
+}
+
+static void dmi_processor_frequency(const u8 *p)
+{
+       u16 code = WORD(p);
+
+       if (code)
+               printf("%u MHz", code);
+       else
+               printf("Unknown");
+}
+
+/* code is assumed to be a 3-bit value */
+static const char *dmi_processor_status(u8 code)
+{
+       static const char *status[] = {
+               "Unknown", /* 0x00 */
+               "Enabled",
+               "Disabled By User",
+               "Disabled By BIOS",
+               "Idle", /* 0x04 */
+               out_of_spec,
+               out_of_spec,
+               "Other" /* 0x07 */
+       };
+
+       return status[code];
+}
+
+static const char *dmi_processor_upgrade(u8 code)
+{
+       /* 7.5.5 */
+       static const char *upgrade[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Daughter Board",
+               "ZIF Socket",
+               "Replaceable Piggy Back",
+               "None",
+               "LIF Socket",
+               "Slot 1",
+               "Slot 2",
+               "370-pin Socket",
+               "Slot A",
+               "Slot M",
+               "Socket 423",
+               "Socket A (Socket 462)",
+               "Socket 478",
+               "Socket 754",
+               "Socket 940",
+               "Socket 939",
+               "Socket mPGA604",
+               "Socket LGA771",
+               "Socket LGA775",
+               "Socket S1",
+               "Socket AM2",
+               "Socket F (1207)",
+               "Socket LGA1366",
+               "Socket G34",
+               "Socket AM3",
+               "Socket C32",
+               "Socket LGA1156",
+               "Socket LGA1567",
+               "Socket PGA988A",
+               "Socket BGA1288" /* 0x20 */
+       };
+
+       if (code >= 0x01 && code <= 0x20)
+               return upgrade[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_processor_cache(u16 code, const char *level, u16 ver)
+{
+       if (code == 0xFFFF)
+       {
+               if (ver >= 0x0203)
+                       printf(" Not Provided");
+               else
+                       printf(" No %s Cache", level);
+       }
+       else
+               printf(" 0x%04X", code);
+}
+
+static void dmi_processor_characteristics(u16 code, const char *prefix)
+{
+       /* 7.5.9 */
+       static const char *characteristics[] = {
+               "64-bit capable", /* 2 */
+               "Multi-Core",
+               "Hardware Thread",
+               "Execute Protection",
+               "Enhanced Virtualization",
+               "Power/Performance Control" /* 7 */
+       };
+
+       if ((code & 0x00FC) == 0)
+               printf(" None\n");
+       else
+       {
+               int i;
+
+               printf("\n");
+               for (i = 2; i <= 7; i++)
+                       if (code & (1 << i))
+                               printf("%s%s\n", prefix, characteristics[i - 2]);
+       }
+}
+
+/*
+ * 7.6 Memory Controller Information (Type 5)
+ */
+
+static const char *dmi_memory_controller_ed_method(u8 code)
+{
+       /* 7.6.1 */
+       static const char *method[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "None",
+               "8-bit Parity",
+               "32-bit ECC",
+               "64-bit ECC",
+               "128-bit ECC",
+               "CRC" /* 0x08 */
+       };
+
+       if (code >= 0x01 && code <= 0x08)
+               return method[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_memory_controller_ec_capabilities(u8 code, const char *prefix)
+{
+       /* 7.6.2 */
+       static const char *capabilities[] = {
+               "Other", /* 0 */
+               "Unknown",
+               "None",
+               "Single-bit Error Correcting",
+               "Double-bit Error Correcting",
+               "Error Scrubbing" /* 5 */
+       };
+
+       if ((code & 0x3F) == 0)
+               printf(" None\n");
+       else
+       {
+               int i;
+
+               printf("\n");
+               for (i = 0; i <= 5; i++)
+                       if (code & (1 << i))
+                               printf("%s%s\n", prefix, capabilities[i]);
+       }
+}
+
+static const char *dmi_memory_controller_interleave(u8 code)
+{
+       /* 7.6.3 */
+       static const char *interleave[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "One-way Interleave",
+               "Two-way Interleave",
+               "Four-way Interleave",
+               "Eight-way Interleave",
+               "Sixteen-way Interleave" /* 0x07 */
+       };
+
+       if (code >= 0x01 && code <= 0x07)
+               return interleave[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_memory_controller_speeds(u16 code, const char *prefix)
+{
+       /* 7.6.4 */
+       const char *speeds[] = {
+               "Other", /* 0 */
+               "Unknown",
+               "70 ns",
+               "60 ns",
+               "50 ns" /* 4 */
+       };
+
+       if ((code & 0x001F) == 0)
+               printf(" None\n");
+       else
+       {
+               int i;
+
+               printf("\n");
+               for (i = 0; i <= 4; i++)
+                       if (code & (1 << i))
+                               printf("%s%s\n", prefix, speeds[i]);
+       }
+}
+
+static void dmi_memory_controller_slots(u8 count, const u8 *p, const char *prefix)
+{
+       int i;
+
+       printf("%sAssociated Memory Slots: %u\n",
+               prefix, count);
+       for (i = 0; i < count; i++)
+               printf("%s\t0x%04X\n",
+                       prefix, WORD(p + sizeof(u16) * i));
+}
+
+/*
+ * 7.7 Memory Module Information (Type 6)
+ */
+
+static void dmi_memory_module_types(u16 code, const char *sep)
+{
+       /* 7.7.1 */
+       static const char *types[] = {
+               "Other", /* 0 */
+               "Unknown",
+               "Standard",
+               "FPM",
+               "EDO",
+               "Parity",
+               "ECC",
+               "SIMM",
+               "DIMM",
+               "Burst EDO",
+               "SDRAM" /* 10 */
+       };
+
+       if ((code & 0x07FF) == 0)
+               printf(" None");
+       else
+       {
+               int i;
+
+               for (i = 0; i <= 10; i++)
+                       if (code & (1 << i))
+                               printf("%s%s", sep, types[i]);
+       }
+}
+
+static void dmi_memory_module_connections(u8 code)
+{
+       if (code == 0xFF)
+               printf(" None");
+       else
+       {
+               if ((code & 0xF0) != 0xF0)
+                       printf(" %u", code >> 4);
+               if ((code & 0x0F) != 0x0F)
+                       printf(" %u", code & 0x0F);
+       }
+}
+
+static void dmi_memory_module_speed(u8 code)
+{
+       if (code == 0)
+               printf(" Unknown");
+       else
+               printf(" %u ns", code);
+}
+
+static void dmi_memory_module_size(u8 code)
+{
+       /* 7.7.2 */
+       switch (code & 0x7F)
+       {
+               case 0x7D:
+                       printf(" Not Determinable");
+                       break;
+               case 0x7E:
+                       printf(" Disabled");
+                       break;
+               case 0x7F:
+                       printf(" Not Installed");
+                       return;
+               default:
+                       printf(" %u MB", 1 << (code & 0x7F));
+       }
+
+       if (code & 0x80)
+               printf(" (Double-bank Connection)");
+       else
+               printf(" (Single-bank Connection)");
+}
+
+static void dmi_memory_module_error(u8 code, const char *prefix)
+{
+       if (code & (1 << 2))
+               printf(" See Event Log\n");
+       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);
+       }
+}
+
+/*
+ * 7.8 Cache Information (Type 7)
+ */
+
+static const char *dmi_cache_mode(u8 code)
+{
+       static const char *mode[] = {
+               "Write Through", /* 0x00 */
+               "Write Back",
+               "Varies With Memory Address",
+               "Unknown" /* 0x03 */
+       };
+
+       return mode[code];
+}
+
+/* code is assumed to be a 2-bit value */
+static const char *dmi_cache_location(u8 code)
+{
+       static const char *location[4] = {
+               "Internal", /* 0x00 */
+               "External",
+               out_of_spec, /* 0x02 */
+               "Unknown" /* 0x03 */
+       };
+
+       return location[code];
+}
+
+static void dmi_cache_size(u16 code)
+{
+       if (code & 0x8000)
+               printf(" %u kB", (code & 0x7FFF) << 6);
+       else
+               printf(" %u kB", code);
+}
+
+static void dmi_cache_types(u16 code, const char *sep)
+{
+       /* 7.8.2 */
+       static const char *types[] = {
+               "Other", /* 0 */
+               "Unknown",
+               "Non-burst",
+               "Burst",
+               "Pipeline Burst",
+               "Synchronous",
+               "Asynchronous" /* 6 */
+       };
+
+       if ((code & 0x007F) == 0)
+               printf(" None");
+       else
+       {
+               int i;
+
+               for (i = 0; i <= 6; i++)
+                       if (code & (1 << i))
+                               printf("%s%s", sep, types[i]);
+       }
+}
+
+static const char *dmi_cache_ec_type(u8 code)
+{
+       /* 7.8.3 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "None",
+               "Parity",
+               "Single-bit ECC",
+               "Multi-bit ECC" /* 0x06 */
+       };
+
+       if (code >= 0x01 && code <= 0x06)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_cache_type(u8 code)
+{
+       /* 7.8.4 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Instruction",
+               "Data",
+               "Unified" /* 0x05 */
+       };
+
+       if (code >= 0x01 && code <= 0x05)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_cache_associativity(u8 code)
+{
+       /* 7.8.5 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Direct Mapped",
+               "2-way Set-associative",
+               "4-way Set-associative",
+               "Fully Associative",
+               "8-way Set-associative",
+               "16-way Set-associative",
+               "12-way Set-associative",
+               "24-way Set-associative",
+               "32-way Set-associative",
+               "48-way Set-associative",
+               "64-way Set-associative" /* 0x0D */
+       };
+
+       if (code >= 0x01 && code <= 0x0D)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+/*
+ * 7.9 Port Connector Information (Type 8)
+ */
+
+static const char *dmi_port_connector_type(u8 code)
+{
+       /* 7.9.2 */
+       static const char *type[] = {
+               "None", /* 0x00 */
+               "Centronics",
+               "Mini Centronics",
+               "Proprietary",
+               "DB-25 male",
+               "DB-25 female",
+               "DB-15 male",
+               "DB-15 female",
+               "DB-9 male",
+               "DB-9 female",
+               "RJ-11",
+               "RJ-45",
+               "50 Pin MiniSCSI",
+               "Mini DIN",
+               "Micro DIN",
+               "PS/2",
+               "Infrared",
+               "HP-HIL",
+               "Access Bus (USB)",
+               "SSA SCSI",
+               "Circular DIN-8 male",
+               "Circular DIN-8 female",
+               "On Board IDE",
+               "On Board Floppy",
+               "9 Pin Dual Inline (pin 10 cut)",
+               "25 Pin Dual Inline (pin 26 cut)",
+               "50 Pin Dual Inline",
+               "68 Pin Dual Inline",
+               "On Board Sound Input From CD-ROM",
+               "Mini Centronics Type-14",
+               "Mini Centronics Type-26",
+               "Mini Jack (headphones)",
+               "BNC",
+               "IEEE 1394",
+               "SAS/SATA Plug Receptacle" /* 0x22 */
+       };
+       static const char *type_0xA0[] = {
+               "PC-98", /* 0xA0 */
+               "PC-98 Hireso",
+               "PC-H98",
+               "PC-98 Note",
+               "PC-98 Full" /* 0xA4 */
+       };
+
+       if (code <= 0x22)
+               return type[code];
+       if (code >= 0xA0 && code <= 0xA4)
+               return type_0xA0[code - 0xA0];
+       if (code == 0xFF)
+               return "Other";
+       return out_of_spec;
+}
+
+static const char *dmi_port_type(u8 code)
+{
+       /* 7.9.3 */
+       static const char *type[] = {
+               "None", /* 0x00 */
+               "Parallel Port XT/AT Compatible",
+               "Parallel Port PS/2",
+               "Parallel Port ECP",
+               "Parallel Port EPP",
+               "Parallel Port ECP/EPP",
+               "Serial Port XT/AT Compatible",
+               "Serial Port 16450 Compatible",
+               "Serial Port 16550 Compatible",
+               "Serial Port 16550A Compatible",
+               "SCSI Port",
+               "MIDI Port",
+               "Joystick Port",
+               "Keyboard Port",
+               "Mouse Port",
+               "SSA SCSI",
+               "USB",
+               "Firewire (IEEE P1394)",
+               "PCMCIA Type I",
+               "PCMCIA Type II",
+               "PCMCIA Type III",
+               "Cardbus",
+               "Access Bus Port",
+               "SCSI II",
+               "SCSI Wide",
+               "PC-98",
+               "PC-98 Hireso",
+               "PC-H98",
+               "Video Port",
+               "Audio Port",
+               "Modem Port",
+               "Network Port",
+               "SATA",
+               "SAS" /* 0x21 */
+       };
+       static const char *type_0xA0[] = {
+               "8251 Compatible", /* 0xA0 */
+               "8251 FIFO Compatible" /* 0xA1 */
+       };
+
+       if (code <= 0x21)
+               return type[code];
+       if (code >= 0xA0 && code <= 0xA1)
+               return type_0xA0[code - 0xA0];
+       if (code == 0xFF)
+               return "Other";
+       return out_of_spec;
+}
+
+/*
+ * 7.10 System Slots (Type 9)
+ */
+
+static const char *dmi_slot_type(u8 code)
+{
+       /* 7.10.1 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "ISA",
+               "MCA",
+               "EISA",
+               "PCI",
+               "PC Card (PCMCIA)",
+               "VLB",
+               "Proprietary",
+               "Processor Card",
+               "Proprietary Memory Card",
+               "I/O Riser Card",
+               "NuBus",
+               "PCI-66",
+               "AGP",
+               "AGP 2x",
+               "AGP 4x",
+               "PCI-X",
+               "AGP 8x" /* 0x13 */
+       };
+       static const char *type_0xA0[] = {
+               "PC-98/C20", /* 0xA0 */
+               "PC-98/C24",
+               "PC-98/E",
+               "PC-98/Local Bus",
+               "PC-98/Card",
+               "PCI Express",
+               "PCI Express x1",
+               "PCI Express x2",
+               "PCI Express x4",
+               "PCI Express x8",
+               "PCI Express x16",
+               "PCI Express 2",
+               "PCI Express 2 x1",
+               "PCI Express 2 x2",
+               "PCI Express 2 x4",
+               "PCI Express 2 x8",
+               "PCI Express 2 x16", /* 0xB0 */
+       };
+
+       if (code >= 0x01 && code <= 0x13)
+               return type[code - 0x01];
+       if (code >= 0xA0 && code <= 0xB0)
+               return type_0xA0[code - 0xA0];
+       return out_of_spec;
+}
+
+static const char *dmi_slot_bus_width(u8 code)
+{
+       /* 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 */
+       };
+
+       if (code >= 0x01 && code <= 0x0E)
+               return width[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_slot_current_usage(u8 code)
+{
+       /* 7.10.3 */
+       static const char *usage[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Available",
+               "In Use" /* 0x04 */
+       };
+
+       if (code >= 0x01 && code <= 0x04)
+               return usage[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_slot_length(u8 code)
+{
+       /* 7.1O.4 */
+       static const char *length[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Short",
+               "Long" /* 0x04 */
+       };
+
+       if (code >= 0x01 && code <= 0x04)
+               return length[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_slot_id(u8 code1, u8 code2, u8 type, const char *prefix)
+{
+       /* 7.10.5 */
+       switch (type)
+       {
+               case 0x04: /* MCA */
+                       printf("%sID: %u\n", prefix, code1);
+                       break;
+               case 0x05: /* EISA */
+                       printf("%sID: %u\n", prefix, code1);
+                       break;
+               case 0x06: /* PCI */
+               case 0x0E: /* PCI */
+               case 0x0F: /* AGP */
+               case 0x10: /* AGP */
+               case 0x11: /* AGP */
+               case 0x12: /* PCI-X */
+               case 0x13: /* AGP */
+               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 */
+                       printf("%sID: %u\n", prefix, code1);
+                       break;
+               case 0x07: /* PCMCIA */
+                       printf("%sID: Adapter %u, Socket %u\n", prefix, code1, code2);
+                       break;
+       }
+}
+
+static void dmi_slot_characteristics(u8 code1, u8 code2, const char *prefix)
+{
+       /* 7.10.6 */
+       static const char *characteristics1[] = {
+               "5.0 V is provided", /* 1 */
+               "3.3 V is provided",
+               "Opening is shared",
+               "PC Card-16 is supported",
+               "Cardbus is supported",
+               "Zoom Video is supported",
+               "Modem ring resume is supported" /* 7 */
+       };
+       /* 7.10.7 */
+       static const char *characteristics2[] = {
+               "PME signal is supported", /* 0 */
+               "Hot-plug devices are supported",
+               "SMBus signal is supported" /* 2 */
+       };
+
+       if (code1 & (1 << 0))
+               printf(" Unknown\n");
+       else if ((code1 & 0xFE) == 0 && (code2 & 0x07) == 0)
+               printf(" None\n");
+       else
+       {
+               int i;
+
+               printf("\n");
+               for (i = 1; i <= 7; i++)
+                       if (code1 & (1 << i))
+                               printf("%s%s\n", prefix, characteristics1[i - 1]);
+               for (i = 0; i <= 2; i++)
+                       if (code2 & (1 << i))
+                               printf("%s%s\n", prefix, characteristics2[i]);
+       }
+}
+
+static void dmi_slot_segment_bus_func(u16 code1, u8 code2, u8 code3, const char *prefix)
+{
+       /* 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);
+}
+
+/*
+ * 7.11 On Board Devices Information (Type 10)
+ */
+
+static const char *dmi_on_board_devices_type(u8 code)
+{
+       /* 7.11.1 and 7.42.2 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Video",
+               "SCSI Controller",
+               "Ethernet",
+               "Token Ring",
+               "Sound",
+               "PATA Controller",
+               "SATA Controller",
+               "SAS Controller" /* 0x0A */
+       };
+
+       if (code >= 0x01 && code <= 0x0A)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_on_board_devices(const struct dmi_header *h, const char *prefix)
+{
+       u8 *p = h->data + 4;
+       u8 count = (h->length - 0x04) / 2;
+       int i;
+
+       for (i = 0; i < count; i++)
+       {
+               if (count == 1)
+                       printf("%sOn Board Device Information\n",
+                               prefix);
+               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]));
+       }
+}
+
+/*
+ * 7.12 OEM Strings (Type 11)
+ */
+
+static void dmi_oem_strings(const struct dmi_header *h, const char *prefix)
+{
+       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));
+}
+
+/*
+ * 7.13 System Configuration Options (Type 12)
+ */
+
+static void dmi_system_configuration_options(const struct dmi_header *h, const char *prefix)
+{
+       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));
+}
+
+/*
+ * 7.14 BIOS Language Information (Type 13)
+ */
+
+static void dmi_bios_languages(const struct dmi_header *h, const char *prefix)
+{
+       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));
+}
+
+static const char *dmi_bios_language_format(u8 code)
+{
+       if (code & 0x01)
+               return "Abbreviated";
+       else
+               return "Long";
+}
+
+/*
+ * 7.15 Group Associations (Type 14)
+ */
+
+static void dmi_group_associations_items(u8 count, const u8 *p, const char *prefix)
+{
+       int i;
+
+       for (i = 0; i < count; i++)
+       {
+               printf("%s0x%04X (%s)\n",
+                       prefix, WORD(p + 3 * i + 1),
+                       dmi_smbios_structure_type(p[3 * i]));
+       }
+}
+
+/*
+ * 7.16 System Event Log (Type 15)
+ */
+
+static const char *dmi_event_log_method(u8 code)
+{
+       static const char *method[] = {
+               "Indexed I/O, one 8-bit index port, one 8-bit data port", /* 0x00 */
+               "Indexed I/O, two 8-bit index ports, one 8-bit data port",
+               "Indexed I/O, one 16-bit index port, one 8-bit data port",
+               "Memory-mapped physical 32-bit address",
+               "General-purpose non-volatile data functions" /* 0x04 */
+       };
+
+       if (code <= 0x04)
+               return method[code];
+       if (code >= 0x80)
+               return "OEM-specific";
+       return out_of_spec;
+}
+
+static void dmi_event_log_status(u8 code)
+{
+       static const char *valid[] = {
+               "Invalid", /* 0 */
+               "Valid" /* 1 */
+       };
+       static const char *full[] = {
+               "Not Full", /* 0 */
+               "Full" /* 1 */
+       };
+
+       printf(" %s, %s",
+               valid[(code >> 0) & 1], full[(code >> 1) & 1]);
+}
+
+static void dmi_event_log_address(u8 method, const u8 *p)
+{
+       /* 7.16.3 */
+       switch (method)
+       {
+               case 0x00:
+               case 0x01:
+               case 0x02:
+                       printf(" Index 0x%04X, Data 0x%04X", WORD(p), WORD(p + 2));
+                       break;
+               case 0x03:
+                       printf(" 0x%08X", DWORD(p));
+                       break;
+               case 0x04:
+                       printf(" 0x%04X", WORD(p));
+                       break;
+               default:
+                       printf(" Unknown");
+       }
+}
+
+static const char *dmi_event_log_header_type(u8 code)
+{
+       static const char *type[] = {
+               "No Header", /* 0x00 */
+               "Type 1" /* 0x01 */
+       };
+
+       if (code <= 0x01)
+               return type[code];
+       if (code >= 0x80)
+               return "OEM-specific";
+       return out_of_spec;
+}
+
+static const char *dmi_event_log_descriptor_type(u8 code)
+{
+       /* 7.16.6.1 */
+       static const char *type[] = {
+               NULL, /* 0x00 */
+               "Single-bit ECC memory error",
+               "Multi-bit ECC memory error",
+               "Parity memory error",
+               "Bus timeout",
+               "I/O channel block",
+               "Software NMI",
+               "POST memory resize",
+               "POST error",
+               "PCI parity error",
+               "PCI system error",
+               "CPU failure",
+               "EISA failsafe timer timeout",
+               "Correctable memory log disabled",
+               "Logging disabled",
+               NULL, /* 0x0F */
+               "System limit exceeded",
+               "Asynchronous hardware timer expired",
+               "System configuration information",
+               "Hard disk information",
+               "System reconfigured",
+               "Uncorrectable CPU-complex error",
+               "Log area reset/cleared",
+               "System boot" /* 0x17 */
+       };
+
+       if (code <= 0x17 && type[code] != NULL)
+               return type[code];
+       if (code >= 0x80 && code <= 0xFE)
+               return "OEM-specific";
+       if (code == 0xFF)
+               return "End of log";
+       return out_of_spec;
+}
+
+static const char *dmi_event_log_descriptor_format(u8 code)
+{
+       /* 7.16.6.2 */
+       static const char *format[] = {
+               "None", /* 0x00 */
+               "Handle",
+               "Multiple-event",
+               "Multiple-event handle",
+               "POST results bitmap",
+               "System management",
+               "Multiple-event system management" /* 0x06 */
+       };
+
+       if (code <= 0x06)
+               return format[code];
+       if (code >= 0x80)
+               return "OEM-specific";
+       return out_of_spec;
+}
+
+static void dmi_event_log_descriptors(u8 count, u8 len, const u8 *p, const char *prefix)
+{
+       /* 7.16.1 */
+       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]));
+               }
+       }
+}
+
+/*
+ * 7.17 Physical Memory Array (Type 16)
+ */
+
+static const char *dmi_memory_array_location(u8 code)
+{
+       /* 7.17.1 */
+       static const char *location[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "System Board Or Motherboard",
+               "ISA Add-on Card",
+               "EISA Add-on Card",
+               "PCI Add-on Card",
+               "MCA Add-on Card",
+               "PCMCIA Add-on Card",
+               "Proprietary Add-on Card",
+               "NuBus" /* 0x0A */
+       };
+       static const char *location_0xA0[] = {
+               "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 */
+       };
+
+       if (code >= 0x01 && code <= 0x0A)
+               return location[code - 0x01];
+       if (code >= 0xA0 && code <= 0xA4)
+               return location_0xA0[code - 0xA0];
+       return out_of_spec;
+}
+
+static const char *dmi_memory_array_use(u8 code)
+{
+       /* 7.17.2 */
+       static const char *use[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "System Memory",
+               "Video Memory",
+               "Flash Memory",
+               "Non-volatile RAM",
+               "Cache Memory" /* 0x07 */
+       };
+
+       if (code >= 0x01 && code <= 0x07)
+               return use[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_memory_array_ec_type(u8 code)
+{
+       /* 7.17.3 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "None",
+               "Parity",
+               "Single-bit ECC",
+               "Multi-bit ECC",
+               "CRC" /* 0x07 */
+       };
+
+       if (code >= 0x01 && code <= 0x07)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_memory_array_error_handle(u16 code)
+{
+       if (code == 0xFFFE)
+               printf(" Not Provided");
+       else if (code == 0xFFFF)
+               printf(" No Error");
+       else
+               printf(" 0x%04X", code);
+}
+
+/*
+ * 7.18 Memory Device (Type 17)
+ */
+
+static void dmi_memory_device_width(u16 code)
+{
+       /*
+        * If no memory module is present, width may be 0
+        */
+       if (code == 0xFFFF || code == 0)
+               printf(" Unknown");
+       else
+               printf(" %u bits", code);
+}
+
+static void dmi_memory_device_size(u16 code)
+{
+       if (code == 0)
+               printf(" No Module Installed");
+       else if (code == 0xFFFF)
+               printf(" Unknown");
+       else
+       {
+               if (code & 0x8000)
+                       printf(" %u kB", code & 0x7FFF);
+               else
+                       printf(" %u MB", code);
+       }
+}
+
+static void dmi_memory_device_extended_size(u32 code)
+{
+       code &= 0x7FFFFFFFUL;
+
+       /* Use the most suitable unit depending on size */
+       if (code & 0x3FFUL)
+               printf(" %lu MB", (unsigned long)code);
+       else if (code & 0xFFFFFUL)
+               printf(" %lu GB", (unsigned long)code >> 10);
+       else
+               printf(" %lu TB", (unsigned long)code >> 20);
+}
+
+static const char *dmi_memory_device_form_factor(u8 code)
+{
+       /* 7.18.1 */
+       static const char *form_factor[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "SIMM",
+               "SIP",
+               "Chip",
+               "DIP",
+               "ZIP",
+               "Proprietary Card",
+               "DIMM",
+               "TSOP",
+               "Row Of Chips",
+               "RIMM",
+               "SODIMM",
+               "SRIMM",
+               "FB-DIMM" /* 0x0F */
+       };
+
+       if (code >= 0x01 && code <= 0x0F)
+               return form_factor[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_memory_device_set(u8 code)
+{
+       if (code == 0)
+               printf(" None");
+       else if (code == 0xFF)
+               printf(" Unknown");
+       else
+               printf(" %u", code);
+}
+
+static const char *dmi_memory_device_type(u8 code)
+{
+       /* 7.18.2 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "DRAM",
+               "EDRAM",
+               "VRAM",
+               "SRAM",
+               "RAM",
+               "ROM",
+               "Flash",
+               "EEPROM",
+               "FEPROM",
+               "EPROM",
+               "CDRAM",
+               "3DRAM",
+               "SDRAM",
+               "SGRAM",
+               "RDRAM",
+               "DDR",
+               "DDR2",
+               "DDR2 FB-DIMM",
+               "Reserved",
+               "Reserved",
+               "Reserved",
+               "DDR3",
+               "FBD2", /* 0x19 */
+       };
+
+       if (code >= 0x01 && code <= 0x19)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_memory_device_type_detail(u16 code)
+{
+       /* 7.18.3 */
+       static const char *detail[] = {
+               "Other", /* 1 */
+               "Unknown",
+               "Fast-paged",
+               "Static Column",
+               "Pseudo-static",
+               "RAMBus",
+               "Synchronous",
+               "CMOS",
+               "EDO",
+               "Window DRAM",
+               "Cache DRAM",
+               "Non-Volatile",
+               "Registered (Buffered)",
+               "Unbuffered (Unregistered)"  /* 14 */
+       };
+
+       if ((code & 0x7FFE) == 0)
+               printf(" None");
+       else
+       {
+               int i;
+
+               for (i = 1; i <= 14; i++)
+                       if (code & (1 << i))
+                               printf(" %s", detail[i - 1]);
+       }
+}
+
+static void dmi_memory_device_speed(u16 code)
+{
+       if (code == 0)
+               printf(" Unknown");
+       else
+               printf(" %u MHz", code);
+}
+
+/*
+ * 7.19 32-bit Memory Error Information (Type 18)
+ */
+
+static const char *dmi_memory_error_type(u8 code)
+{
+       /* 7.19.1 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "OK",
+               "Bad Read",
+               "Parity Error",
+               "Single-bit Error",
+               "Double-bit Error",
+               "Multi-bit Error",
+               "Nibble Error",
+               "Checksum Error",
+               "CRC Error",
+               "Corrected Single-bit Error",
+               "Corrected Error",
+               "Uncorrectable Error" /* 0x0E */
+       };
+
+       if (code >= 0x01 && code <= 0x0E)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_memory_error_granularity(u8 code)
+{
+       /* 7.19.2 */
+       static const char *granularity[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Device Level",
+               "Memory Partition Level" /* 0x04 */
+       };
+
+       if (code >= 0x01 && code <= 0x04)
+               return granularity[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_memory_error_operation(u8 code)
+{
+       /* 7.19.3 */
+       static const char *operation[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Read",
+               "Write",
+               "Partial Write" /* 0x05 */
+       };
+
+       if (code >= 0x01 && code <= 0x05)
+               return operation[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_memory_error_syndrome(u32 code)
+{
+       if (code == 0x00000000)
+               printf(" Unknown");
+       else
+               printf(" 0x%08X", code);
+}
+
+static void dmi_32bit_memory_error_address(u32 code)
+{
+       if (code == 0x80000000)
+               printf(" Unknown");
+       else
+               printf(" 0x%08X", code);
+}
+
+/*
+ * 7.20 Memory Array Mapped Address (Type 19)
+ */
+
+static void dmi_mapped_address_size(u32 code)
+{
+       if (code == 0)
+               printf(" Invalid");
+       else
+       {
+               u64 size;
+
+               size.h = 0;
+               size.l = code;
+               dmi_print_memory_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");
+       else
+               dmi_print_memory_size(u64_range(start, end), 0);
+}
+
+/*
+ * 7.21 Memory Device Mapped Address (Type 20)
+ */
+
+static void dmi_mapped_address_row_position(u8 code)
+{
+       if (code == 0)
+               printf(" %s", out_of_spec);
+       else if (code == 0xFF)
+               printf(" Unknown");
+       else
+               printf(" %u", code);
+}
+
+static void dmi_mapped_address_interleave_position(u8 code, const char *prefix)
+{
+       if (code != 0)
+       {
+               printf("%sInterleave Position:", prefix);
+               if (code == 0xFF)
+                       printf(" Unknown");
+               else
+                       printf(" %u", code);
+               printf("\n");
+       }
+}
+
+static void dmi_mapped_address_interleaved_data_depth(u8 code, const char *prefix)
+{
+       if (code != 0)
+       {
+               printf("%sInterleaved Data Depth:", prefix);
+               if (code == 0xFF)
+                       printf(" Unknown");
+               else
+                       printf(" %u", code);
+               printf("\n");
+       }
+}
+
+/*
+ * 7.22 Built-in Pointing Device (Type 21)
+ */
+
+static const char *dmi_pointing_device_type(u8 code)
+{
+       /* 7.22.1 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Mouse",
+               "Track Ball",
+               "Track Point",
+               "Glide Point",
+               "Touch Pad",
+               "Touch Screen",
+               "Optical Sensor" /* 0x09 */
+       };
+
+       if (code >= 0x01 && code <= 0x09)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_pointing_device_interface(u8 code)
+{
+       /* 7.22.2 */
+       static const char *interface[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Serial",
+               "PS/2",
+               "Infrared",
+               "HIP-HIL",
+               "Bus Mouse",
+               "ADB (Apple Desktop Bus)" /* 0x08 */
+       };
+       static const char *interface_0xA0[] = {
+               "Bus Mouse DB-9", /* 0xA0 */
+               "Bus Mouse Micro DIN",
+               "USB" /* 0xA2 */
+       };
+
+       if (code >= 0x01 && code <= 0x08)
+               return interface[code - 0x01];
+       if (code >= 0xA0 && code <= 0xA2)
+               return interface_0xA0[code - 0xA0];
+       return out_of_spec;
+}
+
+/*
+ * 7.23 Portable Battery (Type 22)
+ */
+
+static const char *dmi_battery_chemistry(u8 code)
+{
+       /* 7.23.1 */
+       static const char *chemistry[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Lead Acid",
+               "Nickel Cadmium",
+               "Nickel Metal Hydride",
+               "Lithium Ion",
+               "Zinc Air",
+               "Lithium Polymer" /* 0x08 */
+       };
+
+       if (code >= 0x01 && code <= 0x08)
+               return chemistry[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_battery_capacity(u16 code, u8 multiplier)
+{
+       if (code == 0)
+               printf(" Unknown");
+       else
+               printf(" %u mWh", code * multiplier);
+}
+
+static void dmi_battery_voltage(u16 code)
+{
+       if (code == 0)
+               printf(" Unknown");
+       else
+               printf(" %u mV", code);
+}
+
+static void dmi_battery_maximum_error(u8 code)
+{
+       if (code == 0xFF)
+               printf(" Unknown");
+       else
+               printf(" %u%%", code);
+}
+
+/*
+ * 7.24 System Reset (Type 23)
+ */
+
+/* code is assumed to be a 2-bit value */
+static const char *dmi_system_reset_boot_option(u8 code)
+{
+       static const char *option[] = {
+               out_of_spec, /* 0x0 */
+               "Operating System", /* 0x1 */
+               "System Utilities",
+               "Do Not Reboot" /* 0x3 */
+       };
+
+       return option[code];
+}
+
+static void dmi_system_reset_count(u16 code)
+{
+       if (code == 0xFFFF)
+               printf(" Unknown");
+       else
+               printf(" %u", code);
+}
+
+static void dmi_system_reset_timer(u16 code)
+{
+       if (code == 0xFFFF)
+               printf(" Unknown");
+       else
+               printf(" %u min", code);
+}
+
+/*
+ * 7.25 Hardware Security (Type 24)
+ */
+
+static const char *dmi_hardware_security_status(u8 code)
+{
+       static const char *status[] = {
+               "Disabled", /* 0x00 */
+               "Enabled",
+               "Not Implemented",
+               "Unknown" /* 0x03 */
+       };
+
+       return status[code];
+}
+
+/*
+ * 7.26 System Power Controls (Type 25)
+ */
+
+static void dmi_power_controls_power_on(const u8 *p)
+{
+       /* 7.26.1 */
+       if (dmi_bcd_range(p[0], 0x01, 0x12))
+               printf(" %02X", p[0]);
+       else
+               printf(" *");
+       if (dmi_bcd_range(p[1], 0x01, 0x31))
+               printf("-%02X", p[1]);
+       else
+               printf("-*");
+       if (dmi_bcd_range(p[2], 0x00, 0x23))
+               printf(" %02X", p[2]);
+       else
+               printf(" *");
+       if (dmi_bcd_range(p[3], 0x00, 0x59))
+               printf(":%02X", p[3]);
+       else
+               printf(":*");
+       if (dmi_bcd_range(p[4], 0x00, 0x59))
+               printf(":%02X", p[4]);
+       else
+               printf(":*");
+}
+
+/*
+ * 7.27 Voltage Probe (Type 26)
+ */
+
+static const char *dmi_voltage_probe_location(u8 code)
+{
+       /* 7.27.1 */
+       static const char *location[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Processor",
+               "Disk",
+               "Peripheral Bay",
+               "System Management Module",
+               "Motherboard",
+               "Memory Module",
+               "Processor Module",
+               "Power Unit",
+               "Add-in Card" /* 0x0B */
+       };
+
+       if (code >= 0x01 && code <= 0x0B)
+               return location[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_probe_status(u8 code)
+{
+       /* 7.27.1 */
+       static const char *status[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "OK",
+               "Non-critical",
+               "Critical",
+               "Non-recoverable" /* 0x06 */
+       };
+
+       if (code >= 0x01 && code <= 0x06)
+               return status[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_voltage_probe_value(u16 code)
+{
+       if (code == 0x8000)
+               printf(" Unknown");
+       else
+               printf(" %.3f V", (float)(i16)code / 1000);
+}
+
+static void dmi_voltage_probe_resolution(u16 code)
+{
+       if (code == 0x8000)
+               printf(" Unknown");
+       else
+               printf(" %.1f mV", (float)code / 10);
+}
+
+static void dmi_probe_accuracy(u16 code)
+{
+       if (code == 0x8000)
+               printf(" Unknown");
+       else
+               printf(" %.2f%%", (float)code / 100);
+}
+
+/*
+ * 7.28 Cooling Device (Type 27)
+ */
+
+static const char *dmi_cooling_device_type(u8 code)
+{
+       /* 7.28.1 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Fan",
+               "Centrifugal Blower",
+               "Chip Fan",
+               "Cabinet Fan",
+               "Power Supply Fan",
+               "Heat Pipe",
+               "Integrated Refrigeration" /* 0x09 */
+       };
+       static const char *type_0x10[] = {
+               "Active Cooling", /* 0x10 */
+               "Passive Cooling" /* 0x11 */
+       };
+
+       if (code >= 0x01 && code <= 0x09)
+               return type[code - 0x01];
+       if (code >= 0x10 && code <= 0x11)
+               return type_0x10[code - 0x10];
+       return out_of_spec;
+}
+
+static void dmi_cooling_device_speed(u16 code)
+{
+       if (code == 0x8000)
+               printf(" Unknown Or Non-rotating");
+       else
+               printf(" %u rpm", code);
+}
+
+/*
+ * 7.29 Temperature Probe (Type 28)
+ */
+
+static const char *dmi_temperature_probe_location(u8 code)
+{
+       /* 7.29.1 */
+       static const char *location[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Processor",
+               "Disk",
+               "Peripheral Bay",
+               "System Management Module",
+               "Motherboard",
+               "Memory Module",
+               "Processor Module",
+               "Power Unit",
+               "Add-in Card",
+               "Front Panel Board",
+               "Back Panel Board",
+               "Power System Board",
+               "Drive Back Plane" /* 0x0F */
+       };
+
+       if (code >= 0x01 && code <= 0x0F)
+               return location[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_temperature_probe_value(u16 code)
+{
+       if (code == 0x8000)
+               printf(" Unknown");
+       else
+               printf(" %.1f deg C", (float)(i16)code / 10);
+}
+
+static void dmi_temperature_probe_resolution(u16 code)
+{
+       if (code == 0x8000)
+               printf(" Unknown");
+       else
+               printf(" %.3f deg C", (float)code / 1000);
+}
+
+/*
+ * 7.30 Electrical Current Probe (Type 29)
+ */
+
+static void dmi_current_probe_value(u16 code)
+{
+       if (code == 0x8000)
+               printf(" Unknown");
+       else
+               printf(" %.3f A", (float)(i16)code / 1000);
+}
+
+static void dmi_current_probe_resolution(u16 code)
+{
+       if (code == 0x8000)
+               printf(" Unknown");
+       else
+               printf(" %.1f mA", (float)code / 10);
+}
+
+/*
+ * 7.33 System Boot Information (Type 32)
+ */
+
+static const char *dmi_system_boot_status(u8 code)
+{
+       static const char *status[] = {
+               "No errors detected", /* 0 */
+               "No bootable media",
+               "Operating system failed to load",
+               "Firmware-detected hardware failure",
+               "Operating system-detected hardware failure",
+               "User-requested boot",
+               "System security violation",
+               "Previously-requested image",
+               "System watchdog timer expired" /* 8 */
+       };
+
+       if (code <= 8)
+               return status[code];
+       if (code >= 128 && code <= 191)
+               return "OEM-specific";
+       if (code >= 192)
+               return "Product-specific";
+       return out_of_spec;
+}
+
+/*
+ * 7.34 64-bit Memory Error Information (Type 33)
+ */
+
+static void dmi_64bit_memory_error_address(u64 code)
+{
+       if (code.h == 0x80000000 && code.l == 0x00000000)
+               printf(" Unknown");
+       else
+               printf(" 0x%08X%08X", code.h, code.l);
+}
+
+/*
+ * 7.35 Management Device (Type 34)
+ */
+
+static const char *dmi_management_device_type(u8 code)
+{
+       /* 7.35.1 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "LM75",
+               "LM78",
+               "LM79",
+               "LM80",
+               "LM81",
+               "ADM9240",
+               "DS1780",
+               "MAX1617",
+               "GL518SM",
+               "W83781D",
+               "HT82H791" /* 0x0D */
+       };
+
+       if (code >= 0x01 && code <= 0x0D)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_management_device_address_type(u8 code)
+{
+       /* 7.35.2 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "I/O Port",
+               "Memory",
+               "SMBus" /* 0x05 */
+       };
+
+       if (code >= 0x01 && code <= 0x05)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+/*
+ * 7.38 Memory Channel (Type 37)
+ */
+
+static const char *dmi_memory_channel_type(u8 code)
+{
+       /* 7.38.1 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "RamBus",
+               "SyncLink" /* 0x04 */
+       };
+
+       if (code >= 0x01 && code <= 0x04)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static void dmi_memory_channel_devices(u8 count, const u8 *p, const char *prefix)
+{
+       int i;
+
+       for (i = 1; i <= count; i++)
+       {
+               printf("%sDevice %u Load: %u\n",
+                       prefix, i, p[3 * i]);
+               if (!(opt.flags & FLAG_QUIET))
+                       printf("%sDevice %u Handle: 0x%04X\n",
+                               prefix, i, WORD(p + 3 * i + 1));
+       }
+}
+
+/*
+ * 7.39 IPMI Device Information (Type 38)
+ */
+
+static const char *dmi_ipmi_interface_type(u8 code)
+{
+       /* 7.39.1 and IPMI 2.0, appendix C1, table C1-2 */
+       static const char *type[] = {
+               "Unknown", /* 0x00 */
+               "KCS (Keyboard Control Style)",
+               "SMIC (Server Management Interface Chip)",
+               "BT (Block Transfer)",
+               "SSIF (SMBus System Interface)" /* 0x04 */
+       };
+
+       if (code <= 0x04)
+               return type[code];
+       return out_of_spec;
+}
+
+static void dmi_ipmi_base_address(u8 type, const u8 *p, u8 lsb)
+{
+       if (type == 0x04) /* SSIF */
+       {
+               printf("0x%02X (SMBus)", (*p) >> 1);
+       }
+       else
+       {
+               u64 address = QWORD(p);
+               printf("0x%08X%08X (%s)", address.h, (address.l & ~1) | lsb,
+                       address.l & 1 ? "I/O" : "Memory-mapped");
+       }
+}
+
+/* code is assumed to be a 2-bit value */
+static const char *dmi_ipmi_register_spacing(u8 code)
+{
+       /* IPMI 2.0, appendix C1, table C1-1 */
+       static const char *spacing[] = {
+               "Successive Byte Boundaries", /* 0x00 */
+               "32-bit Boundaries",
+               "16-byte Boundaries", /* 0x02 */
+               out_of_spec /* 0x03 */
+       };
+
+       return spacing[code];
+}
+
+/*
+ * 7.40 System Power Supply (Type 39)
+ */
+
+static void dmi_power_supply_power(u16 code)
+{
+       if (code == 0x8000)
+               printf(" Unknown");
+       else
+               printf(" %u W", (unsigned int)code);
+}
+
+static const char *dmi_power_supply_type(u8 code)
+{
+       /* 7.40.1 */
+       static const char *type[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Linear",
+               "Switching",
+               "Battery",
+               "UPS",
+               "Converter",
+               "Regulator" /* 0x08 */
+       };
+
+       if (code >= 0x01 && code <= 0x08)
+               return type[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_power_supply_status(u8 code)
+{
+       /* 7.40.1 */
+       static const char *status[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "OK",
+               "Non-critical",
+               "Critical" /* 0x05 */
+       };
+
+       if (code >= 0x01 && code <= 0x05)
+               return status[code - 0x01];
+       return out_of_spec;
+}
+
+static const char *dmi_power_supply_range_switching(u8 code)
+{
+       /* 7.40.1 */
+       static const char *switching[] = {
+               "Other", /* 0x01 */
+               "Unknown",
+               "Manual",
+               "Auto-switch",
+               "Wide Range",
+               "N/A" /* 0x06 */
+       };
+
+       if (code >= 0x01 && code <= 0x06)
+               return switching[code - 0x01];
+       return out_of_spec;
+}
+
+/*
+ * 7.41 Additional Information (Type 40)
+ *
+ * Proper support of this 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.
+ */
+
+static void dmi_additional_info(const struct dmi_header *h, const char *prefix)
+{
+       u8 *p = h->data + 4;
+       u8 count = *p++;
+       u8 length;
+       int i, offset = 5;
+
+       for (i = 0; i < count; i++)
+       {
+               printf("%sAdditional Information %d\n", prefix, 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]));
+
+               printf("%s\tValue: ", prefix);
+               switch (length - 0x05)
+               {
+                       case 1:
+                               printf("0x%02x", p[0x05]);
+                               break;
+                       case 2:
+                               printf("0x%04x", WORD(p + 0x05));
+                               break;
+                       case 4:
+                               printf("0x%08x", DWORD(p + 0x05));
+                               break;
+                       default:
+                               printf("Unexpected size");
+                               break;
+               }
+               printf("\n");
+
+               p += length;
+               offset += length;
+       }
+}
+
+/*
+ * 7.43 Management Controller Host Interface (Type 42)
+ */
+
+static const char *dmi_management_controller_host_type(u8 code)
+{
+       /* DMTF DSP0239 (MCTP) version 1.1.0 */
+       static const char *type[] = {
+               "KCS: Keyboard Controller Style", /* 0x02 */
+               "8250 UART Register Compatible",
+               "16450 UART Register Compatible",
+               "16550/16550A UART Register Compatible",
+               "16650/16650A UART Register Compatible",
+               "16750/16750A UART Register Compatible",
+               "16850/16850A UART Register Compatible" /* 0x08 */
+       };
+
+       if (code >= 0x02 && code <= 0x08)
+               return type[code - 0x02];
+       if (code == 0xF0)
+               return "OEM";
+       return out_of_spec;
+}
+
+/*
+ * Main
+ */
+
+static void dmi_decode(const struct dmi_header *h, u16 ver)
+{
+       const u8 *data = h->data;
+
+       /*
+        * Note: DMI types 37, 39 and 40 are untested
+        */
+       switch (h->type)
+       {
+               case 0: /* 7.1 BIOS Information */
+                       printf("BIOS Information\n");
+                       if (h->length < 0x12) break;
+                       printf("\tVendor: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tVersion: %s\n",
+                               dmi_string(h, data[0x05]));
+                       printf("\tRelease Date: %s\n",
+                               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.
+                        */
+                       if (WORD(data + 0x06) != 0)
+                       {
+                               printf("\tAddress: 0x%04X0\n",
+                                       WORD(data + 0x06));
+                               printf("\tRuntime Size:");
+                               dmi_bios_runtime_size((0x10000 - WORD(data + 0x06)) << 4);
+                               printf("\n");
+                       }
+                       printf("\tROM Size: %u kB\n",
+                               (data[0x09] + 1) << 6);
+                       printf("\tCharacteristics:\n");
+                       dmi_bios_characteristics(QWORD(data + 0x0A), "\t\t");
+                       if (h->length < 0x13) break;
+                       dmi_bios_characteristics_x1(data[0x12], "\t\t");
+                       if (h->length < 0x14) break;
+                       dmi_bios_characteristics_x2(data[0x13], "\t\t");
+                       if (h->length < 0x18) break;
+                       if (data[0x14] != 0xFF && data[0x15] != 0xFF)
+                               printf("\tBIOS Revision: %u.%u\n",
+                                       data[0x14], data[0x15]);
+                       if (data[0x16] != 0xFF && data[0x17] != 0xFF)
+                               printf("\tFirmware Revision: %u.%u\n",
+                                       data[0x16], data[0x17]);
+                       break;
+
+               case 1: /* 7.2 System Information */
+                       printf("System Information\n");
+                       if (h->length < 0x08) break;
+                       printf("\tManufacturer: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tProduct Name: %s\n",
+                               dmi_string(h, data[0x05]));
+                       printf("\tVersion: %s\n",
+                               dmi_string(h, data[0x06]));
+                       printf("\tSerial Number: %s\n",
+                               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_wake_up_type(data[0x18]));
+                       if (h->length < 0x1B) break;
+                       printf("\tSKU Number: %s\n",
+                               dmi_string(h, data[0x19]));
+                       printf("\tFamily: %s\n",
+                               dmi_string(h, data[0x1A]));
+                       break;
+
+               case 2: /* 7.3 Base Board Information */
+                       printf("Base Board Information\n");
+                       if (h->length < 0x08) break;
+                       printf("\tManufacturer: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tProduct Name: %s\n",
+                               dmi_string(h, data[0x05]));
+                       printf("\tVersion: %s\n",
+                               dmi_string(h, data[0x06]));
+                       printf("\tSerial Number: %s\n",
+                               dmi_string(h, data[0x07]));
+                       if (h->length < 0x09) break;
+                       printf("\tAsset Tag: %s\n",
+                               dmi_string(h, data[0x08]));
+                       if (h->length < 0x0A) break;
+                       printf("\tFeatures:");
+                       dmi_base_board_features(data[0x09], "\t\t");
+                       if (h->length < 0x0E) break;
+                       printf("\tLocation In Chassis: %s\n",
+                               dmi_string(h, data[0x0A]));
+                       if (!(opt.flags & FLAG_QUIET))
+                               printf("\tChassis Handle: 0x%04X\n",
+                                       WORD(data + 0x0B));
+                       printf("\tType: %s\n",
+                               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");
+                       break;
+
+               case 3: /* 7.4 Chassis Information */
+                       printf("Chassis Information\n");
+                       if (h->length < 0x09) break;
+                       printf("\tManufacturer: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tType: %s\n",
+                               dmi_chassis_type(data[0x05] & 0x7F));
+                       printf("\tLock: %s\n",
+                               dmi_chassis_lock(data[0x05] >> 7));
+                       printf("\tVersion: %s\n",
+                               dmi_string(h, data[0x06]));
+                       printf("\tSerial Number: %s\n",
+                               dmi_string(h, data[0x07]));
+                       printf("\tAsset Tag: %s\n",
+                               dmi_string(h, data[0x08]));
+                       if (h->length < 0x0D) break;
+                       printf("\tBoot-up State: %s\n",
+                               dmi_chassis_state(data[0x09]));
+                       printf("\tPower Supply State: %s\n",
+                               dmi_chassis_state(data[0x0A]));
+                       printf("\tThermal State: %s\n",
+                               dmi_chassis_state(data[0x0B]));
+                       printf("\tSecurity Status: %s\n",
+                               dmi_chassis_security_status(data[0x0C]));
+                       if (h->length < 0x11) break;
+                       printf("\tOEM Information: 0x%08X\n",
+                               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");
+                       if (h->length < 0x16 + data[0x13] * data[0x14]) break;
+                       printf("\tSKU Number: %s\n",
+                               dmi_string(h, data[0x15 + data[0x13] * data[0x14]]));
+                       break;
+
+               case 4: /* 7.5 Processor Information */
+                       printf("Processor Information\n");
+                       if (h->length < 0x1A) break;
+                       printf("\tSocket Designation: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tType: %s\n",
+                               dmi_processor_type(data[0x05]));
+                       printf("\tFamily: %s\n",
+                               dmi_processor_family(h, ver));
+                       printf("\tManufacturer: %s\n",
+                               dmi_string(h, data[0x07]));
+                       dmi_processor_id(data[0x06], data + 0x08, dmi_string(h, data[0x10]), "\t");
+                       printf("\tVersion: %s\n",
+                               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");
+                       if (data[0x18] & (1 << 6))
+                               printf("\tStatus: Populated, %s\n",
+                                       dmi_processor_status(data[0x18] & 0x07));
+                       else
+                               printf("\tStatus: Unpopulated\n");
+                       printf("\tUpgrade: %s\n",
+                               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");
+                       }
+                       if (h->length < 0x23) break;
+                       printf("\tSerial Number: %s\n",
+                               dmi_string(h, data[0x20]));
+                       printf("\tAsset Tag: %s\n",
+                               dmi_string(h, data[0x21]));
+                       printf("\tPart Number: %s\n",
+                               dmi_string(h, data[0x22]));
+                       if (h->length < 0x28) break;
+                       if (data[0x23] != 0)
+                               printf("\tCore Count: %u\n", data[0x23]);
+                       if (data[0x24] != 0)
+                               printf("\tCore Enabled: %u\n", data[0x24]);
+                       if (data[0x25] != 0)
+                               printf("\tThread Count: %u\n", data[0x25]);
+                       printf("\tCharacteristics:");
+                       dmi_processor_characteristics(WORD(data + 0x26), "\t\t");
+                       break;
+
+               case 5: /* 7.6 Memory Controller Information */
+                       printf("Memory Controller Information\n");
+                       if (h->length < 0x0F) break;
+                       printf("\tError Detecting Method: %s\n",
+                               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_interleave(data[0x06]));
+                       printf("\tCurrent Interleave: %s\n",
+                               dmi_memory_controller_interleave(data[0x07]));
+                       printf("\tMaximum Memory Module Size: %u MB\n",
+                               1 << data[0x08]);
+                       printf("\tMaximum Total Memory Size: %u MB\n",
+                               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");
+                       if (h->length < 0x0F + data[0x0E] * sizeof(u16)) break;
+                       dmi_memory_controller_slots(data[0x0E], data + 0x0F, "\t");
+                       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");
+                       break;
+
+               case 6: /* 7.7 Memory Module Information */
+                       printf("Memory Module Information\n");
+                       if (h->length < 0x0C) break;
+                       printf("\tSocket Designation: %s\n",
+                               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");
+                       break;
+
+               case 7: /* 7.8 Cache Information */
+                       printf("Cache Information\n");
+                       if (h->length < 0x0F) break;
+                       printf("\tSocket Designation: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tConfiguration: %s, %s, Level %u\n",
+                               WORD(data + 0x05) & 0x0080 ? "Enabled" : "Disabled",
+                               WORD(data + 0x05) & 0x0008 ? "Socketed" : "Not Socketed",
+                               (WORD(data + 0x05) & 0x0007) + 1);
+                       printf("\tOperational Mode: %s\n",
+                               dmi_cache_mode((WORD(data + 0x05) >> 8) & 0x0003));
+                       printf("\tLocation: %s\n",
+                               dmi_cache_location((WORD(data + 0x05) >> 5) & 0x0003));
+                       printf("\tInstalled Size:");
+                       dmi_cache_size(WORD(data + 0x09));
+                       printf("\n");
+                       printf("\tMaximum Size:");
+                       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");
+                       if (h->length < 0x13) break;
+                       printf("\tSpeed:");
+                       dmi_memory_module_speed(data[0x0F]);
+                       printf("\n");
+                       printf("\tError Correction Type: %s\n",
+                               dmi_cache_ec_type(data[0x10]));
+                       printf("\tSystem Type: %s\n",
+                               dmi_cache_type(data[0x11]));
+                       printf("\tAssociativity: %s\n",
+                               dmi_cache_associativity(data[0x12]));
+                       break;
+
+               case 8: /* 7.9 Port Connector Information */
+                       printf("Port Connector Information\n");
+                       if (h->length < 0x09) break;
+                       printf("\tInternal Reference Designator: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tInternal Connector Type: %s\n",
+                               dmi_port_connector_type(data[0x05]));
+                       printf("\tExternal Reference Designator: %s\n",
+                               dmi_string(h, data[0x06]));
+                       printf("\tExternal Connector Type: %s\n",
+                               dmi_port_connector_type(data[0x07]));
+                       printf("\tPort Type: %s\n",
+                               dmi_port_type(data[0x08]));
+                       break;
+
+               case 9: /* 7.10 System Slots */
+                       printf("System Slot Information\n");
+                       if (h->length < 0x0C) break;
+                       printf("\tDesignation: %s\n",
+                               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_current_usage(data[0x07]));
+                       printf("\tLength: %s\n",
+                               dmi_slot_length(data[0x08]));
+                       dmi_slot_id(data[0x09], data[0x0A], data[0x05], "\t");
+                       printf("\tCharacteristics:");
+                       if (h->length < 0x0D)
+                               dmi_slot_characteristics(data[0x0B], 0x00, "\t\t");
+                       else
+                               dmi_slot_characteristics(data[0x0B], data[0x0C], "\t\t");
+                       if (h->length < 0x11) break;
+                       dmi_slot_segment_bus_func(WORD(data + 0x0D), data[0x0F], data[0x10], "\t");
+                       break;
+
+               case 10: /* 7.11 On Board Devices Information */
+                       dmi_on_board_devices(h, "");
+                       break;
+
+               case 11: /* 7.12 OEM Strings */
+                       printf("OEM Strings\n");
+                       if (h->length < 0x05) break;
+                       dmi_oem_strings(h, "\t");
+                       break;
+
+               case 12: /* 7.13 System Configuration Options */
+                       printf("System Configuration Options\n");
+                       if (h->length < 0x05) break;
+                       dmi_system_configuration_options(h, "\t");
+                       break;
+
+               case 13: /* 7.14 BIOS Language Information */
+                       printf("BIOS Language Information\n");
+                       if (h->length < 0x16) break;
+                       if (ver >= 0x0201)
+                       {
+                               printf("\tLanguage Description Format: %s\n",
+                                       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",
+                               dmi_string(h, data[0x15]));
+                       break;
+
+               case 14: /* 7.15 Group Associations */
+                       printf("Group Associations\n");
+                       if (h->length < 0x05) break;
+                       printf("\tName: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tItems: %u\n",
+                               (h->length - 0x05) / 3);
+                       dmi_group_associations_items((h->length - 0x05) / 3, data + 0x05, "\t\t");
+                       break;
+
+               case 15: /* 7.16 System Event Log */
+                       printf("System Event Log\n");
+                       if (h->length < 0x14) break;
+                       printf("\tArea Length: %u bytes\n",
+                               WORD(data + 0x04));
+                       printf("\tHeader Start Offset: 0x%04X\n",
+                               WORD(data + 0x06));
+                       if (WORD(data + 0x08) - WORD(data + 0x06))
+                               printf("\tHeader Length: %u byte%s\n",
+                                       WORD(data + 0x08) - WORD(data + 0x06),
+                                       WORD(data + 0x08) - WORD(data + 0x06) > 1 ? "s" : "");
+                       printf("\tData Start Offset: 0x%04X\n",
+                               WORD(data + 0x08));
+                       printf("\tAccess Method: %s\n",
+                               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",
+                               DWORD(data + 0x0C));
+                       if (h->length < 0x17) break;
+                       printf("\tHeader Format: %s\n",
+                               dmi_event_log_header_type(data[0x14]));
+                       printf("\tSupported Log Type Descriptors: %u\n",
+                               data[0x15]);
+                       if (h->length < 0x17 + data[0x15] * data[0x16]) break;
+                       dmi_event_log_descriptors(data[0x15], data[0x16], data + 0x17, "\t");
+                       break;
+
+               case 16: /* 7.17 Physical Memory Array */
+                       printf("Physical Memory Array\n");
+                       if (h->length < 0x0F) break;
+                       printf("\tLocation: %s\n",
+                               dmi_memory_array_location(data[0x04]));
+                       printf("\tUse: %s\n",
+                               dmi_memory_array_use(data[0x05]));
+                       printf("\tError Correction Type: %s\n",
+                               dmi_memory_array_ec_type(data[0x06]));
+                       printf("\tMaximum Capacity:");
+                       if (DWORD(data + 0x07) == 0x80000000)
+                       {
+                               if (h->length < 0x17)
+                                       printf(" Unknown");
+                               else
+                                       dmi_print_memory_size(QWORD(data + 0x0F), 0);
+                       }
+                       else
+                       {
+                               u64 capacity;
+
+                               capacity.h = 0;
+                               capacity.l = DWORD(data + 0x07);
+                               dmi_print_memory_size(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",
+                               WORD(data + 0x0D));
+                       break;
+
+               case 17: /* 7.18 Memory Device */
+                       printf("Memory Device\n");
+                       if (h->length < 0x15) break;
+                       if (!(opt.flags & FLAG_QUIET))
+                       {
+                               printf("\tArray Handle: 0x%04X\n",
+                                       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:");
+                       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",
+                               dmi_memory_device_form_factor(data[0x0E]));
+                       printf("\tSet:");
+                       dmi_memory_device_set(data[0x0F]);
+                       printf("\n");
+                       printf("\tLocator: %s\n",
+                               dmi_string(h, data[0x10]));
+                       printf("\tBank Locator: %s\n",
+                               dmi_string(h, data[0x11]));
+                       printf("\tType: %s\n",
+                               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 (h->length < 0x1B) break;
+                       printf("\tManufacturer: %s\n",
+                               dmi_string(h, data[0x17]));
+                       printf("\tSerial Number: %s\n",
+                               dmi_string(h, data[0x18]));
+                       printf("\tAsset Tag: %s\n",
+                               dmi_string(h, data[0x19]));
+                       printf("\tPart Number: %s\n",
+                               dmi_string(h, data[0x1A]));
+                       if (h->length < 0x1C) break;
+                       printf("\tRank: ");
+                       if ((data[0x1B] & 0x0F) == 0)
+                               printf("Unknown");
+                       else
+                               printf("%u", data[0x1B] & 0x0F);
+                       printf("\n");
+                       if (h->length < 0x22) break;
+                       printf("\tConfigured Clock Speed:");
+                       dmi_memory_device_speed(WORD(data + 0x20));
+                       printf("\n");
+                       break;
+
+               case 18: /* 7.19 32-bit Memory Error Information */
+                       printf("32-bit Memory Error Information\n");
+                       if (h->length < 0x17) break;
+                       printf("\tType: %s\n",
+                               dmi_memory_error_type(data[0x04]));
+                       printf("\tGranularity: %s\n",
+                               dmi_memory_error_granularity(data[0x05]));
+                       printf("\tOperation: %s\n",
+                               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");
+                       break;
+
+               case 19: /* 7.20 Memory Array Mapped Address */
+                       printf("Memory Array Mapped Address\n");
+                       if (h->length < 0x0F) break;
+                       if (h->length >= 0x1F && DWORD(data + 0x04) == 0xFFFFFFFF)
+                       {
+                               u64 start, end;
+
+                               start = QWORD(data + 0x0F);
+                               end = QWORD(data + 0x17);
+
+                               printf("\tStarting Address: 0x%08X%08Xk\n",
+                                       start.h, start.l);
+                               printf("\tEnding Address: 0x%08X%08Xk\n",
+                                       end.h, end.l);
+                               printf("\tRange Size:");
+                               dmi_mapped_address_extended_size(start, end);
+                       }
+                       else
+                       {
+                               printf("\tStarting Address: 0x%08X%03X\n",
+                                       DWORD(data + 0x04) >> 2,
+                                       (DWORD(data + 0x04) & 0x3) << 10);
+                               printf("\tEnding Address: 0x%08X%03X\n",
+                                       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",
+                                       WORD(data + 0x0C));
+                       printf("\tPartition Width: %u\n",
+                               data[0x0E]);
+                       break;
+
+               case 20: /* 7.21 Memory Device Mapped Address */
+                       printf("Memory Device Mapped Address\n");
+                       if (h->length < 0x13) break;
+                       if (h->length >= 0x23 && DWORD(data + 0x04) == 0xFFFFFFFF)
+                       {
+                               u64 start, end;
+
+                               start = QWORD(data + 0x13);
+                               end = QWORD(data + 0x1B);
+
+                               printf("\tStarting Address: 0x%08X%08Xk\n",
+                                       start.h, start.l);
+                               printf("\tEnding Address: 0x%08X%08Xk\n",
+                                       end.h, end.l);
+                               printf("\tRange Size:");
+                               dmi_mapped_address_extended_size(start, end);
+                       }
+                       else
+                       {
+                               printf("\tStarting Address: 0x%08X%03X\n",
+                                       DWORD(data + 0x04) >> 2,
+                                       (DWORD(data + 0x04) & 0x3) << 10);
+                               printf("\tEnding Address: 0x%08X%03X\n",
+                                       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",
+                                       WORD(data + 0x0C));
+                               printf("\tMemory Array Mapped Address Handle: 0x%04X\n",
+                                       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");
+                       break;
+
+               case 21: /* 7.22 Built-in Pointing Device */
+                       printf("Built-in Pointing Device\n");
+                       if (h->length < 0x07) break;
+                       printf("\tType: %s\n",
+                               dmi_pointing_device_type(data[0x04]));
+                       printf("\tInterface: %s\n",
+                               dmi_pointing_device_interface(data[0x05]));
+                       printf("\tButtons: %u\n",
+                               data[0x06]);
+                       break;
+
+               case 22: /* 7.23 Portable Battery */
+                       printf("Portable Battery\n");
+                       if (h->length < 0x10) break;
+                       printf("\tLocation: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tManufacturer: %s\n",
+                               dmi_string(h, data[0x05]));
+                       if (data[0x06] || h->length < 0x1A)
+                               printf("\tManufacture Date: %s\n",
+                                       dmi_string(h, data[0x06]));
+                       if (data[0x07] || h->length < 0x1A)
+                               printf("\tSerial Number: %s\n",
+                                       dmi_string(h, data[0x07]));
+                       printf("\tName: %s\n",
+                               dmi_string(h, data[0x08]));
+                       if (data[0x09] != 0x02 || h->length < 0x1A)
+                               printf("\tChemistry: %s\n",
+                                       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",
+                               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",
+                                       WORD(data + 0x10));
+                       if (data[0x06] == 0)
+                               printf("\tSBDS Manufacture Date: %u-%02u-%02u\n",
+                                       1980 + (WORD(data + 0x12) >> 9),
+                                       (WORD(data + 0x12) >> 5) & 0x0F,
+                                       WORD(data + 0x12) & 0x1F);
+                       if (data[0x09] == 0x02)
+                               printf("\tSBDS Chemistry: %s\n",
+                                       dmi_string(h, data[0x14]));
+                       printf("\tOEM-specific Information: 0x%08X\n",
+                               DWORD(data + 0x16));
+                       break;
+
+               case 23: /* 7.24 System Reset */
+                       printf("System Reset\n");
+                       if (h->length < 0x0D) break;
+                       printf("\tStatus: %s\n",
+                               data[0x04] & (1 << 0) ? "Enabled" : "Disabled");
+                       printf("\tWatchdog Timer: %s\n",
+                               data[0x04] & (1 << 5) ? "Present" : "Not Present");
+                       if (!(data[0x04] & (1 << 5)))
+                               break;
+                       printf("\tBoot Option: %s\n",
+                               dmi_system_reset_boot_option((data[0x04] >> 1) & 0x3));
+                       printf("\tBoot Option On Limit: %s\n",
+                               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");
+                       break;
+
+               case 24: /* 7.25 Hardware Security */
+                       printf("Hardware Security\n");
+                       if (h->length < 0x05) break;
+                       printf("\tPower-On Password Status: %s\n",
+                               dmi_hardware_security_status(data[0x04] >> 6));
+                       printf("\tKeyboard Password Status: %s\n",
+                               dmi_hardware_security_status((data[0x04] >> 4) & 0x3));
+                       printf("\tAdministrator Password Status: %s\n",
+                               dmi_hardware_security_status((data[0x04] >> 2) & 0x3));
+                       printf("\tFront Panel Reset Status: %s\n",
+                               dmi_hardware_security_status(data[0x04] & 0x3));
+                       break;
+
+               case 25: /* 7.26 System Power Controls */
+                       printf("\tSystem Power Controls\n");
+                       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");
+                       if (h->length < 0x14) break;
+                       printf("\tDescription: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tLocation: %s\n",
+                               dmi_voltage_probe_location(data[0x05] & 0x1f));
+                       printf("\tStatus: %s\n",
+                               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_resolution(WORD(data + 0x0A));
+                       printf("\n");
+                       printf("\tTolerance:");
+                       dmi_voltage_probe_value(WORD(data + 0x0C));
+                       printf("\n");
+                       printf("\tAccuracy:");
+                       dmi_probe_accuracy(WORD(data + 0x0E));
+                       printf("\n");
+                       printf("\tOEM-specific Information: 0x%08X\n",
+                               DWORD(data + 0x10));
+                       if (h->length < 0x16) break;
+                       printf("\tNominal Value:");
+                       dmi_voltage_probe_value(WORD(data + 0x14));
+                       printf("\n");
+                       break;
+
+               case 27: /* 7.28 Cooling Device */
+                       printf("Cooling Device\n");
+                       if (h->length < 0x0C) break;
+                       if (!(opt.flags & FLAG_QUIET) && WORD(data + 0x04) != 0xFFFF)
+                               printf("\tTemperature Probe Handle: 0x%04X\n",
+                                       WORD(data + 0x04));
+                       printf("\tType: %s\n",
+                               dmi_cooling_device_type(data[0x06] & 0x1f));
+                       printf("\tStatus: %s\n",
+                               dmi_probe_status(data[0x06] >> 5));
+                       if (data[0x07] != 0x00)
+                               printf("\tCooling Unit Group: %u\n",
+                                       data[0x07]);
+                       printf("\tOEM-specific Information: 0x%08X\n",
+                               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]));
+                       break;
+
+               case 28: /* 7.29 Temperature Probe */
+                       printf("Temperature Probe\n");
+                       if (h->length < 0x14) break;
+                       printf("\tDescription: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tLocation: %s\n",
+                               dmi_temperature_probe_location(data[0x05] & 0x1F));
+                       printf("\tStatus: %s\n",
+                               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_resolution(WORD(data + 0x0A));
+                       printf("\n");
+                       printf("\tTolerance:");
+                       dmi_temperature_probe_value(WORD(data + 0x0C));
+                       printf("\n");
+                       printf("\tAccuracy:");
+                       dmi_probe_accuracy(WORD(data + 0x0E));
+                       printf("\n");
+                       printf("\tOEM-specific Information: 0x%08X\n",
+                               DWORD(data + 0x10));
+                       if (h->length < 0x16) break;
+                       printf("\tNominal Value:");
+                       dmi_temperature_probe_value(WORD(data + 0x14));
+                       printf("\n");
+                       break;
+
+               case 29: /* 7.30 Electrical Current Probe */
+                       printf("Electrical Current Probe\n");
+                       if (h->length < 0x14) break;
+                       printf("\tDescription: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tLocation: %s\n",
+                               dmi_voltage_probe_location(data[5] & 0x1F));
+                       printf("\tStatus: %s\n",
+                               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_resolution(WORD(data + 0x0A));
+                       printf("\n");
+                       printf("\tTolerance:");
+                       dmi_current_probe_value(WORD(data + 0x0C));
+                       printf("\n");
+                       printf("\tAccuracy:");
+                       dmi_probe_accuracy(WORD(data + 0x0E));
+                       printf("\n");
+                       printf("\tOEM-specific Information: 0x%08X\n",
+                               DWORD(data + 0x10));
+                       if (h->length < 0x16) break;
+                       printf("\tNominal Value:");
+                       dmi_current_probe_value(WORD(data + 0x14));
+                       printf("\n");
+                       break;
+
+               case 30: /* 7.31 Out-of-band Remote Access */
+                       printf("Out-of-band Remote Access\n");
+                       if (h->length < 0x06) break;
+                       printf("\tManufacturer Name: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tInbound Connection: %s\n",
+                               data[0x05] & (1 << 0) ? "Enabled" : "Disabled");
+                       printf("\tOutbound Connection: %s\n",
+                               data[0x05] & (1 << 1) ? "Enabled" : "Disabled");
+                       break;
+
+               case 31: /* 7.32 Boot Integrity Services Entry Point */
+                       printf("Boot Integrity Services Entry Point\n");
+                       if (h->length < 0x1C) break;
+                       printf("\tChecksum: %s\n",
+                               checksum(data, h->length) ? "OK" : "Invalid");
+                       printf("\t16-bit Entry Point Address: %04X:%04X\n",
+                               DWORD(data + 0x08) >> 16,
+                               DWORD(data + 0x08) & 0xFFFF);
+                       printf("\t32-bit Entry Point Address: 0x%08X\n",
+                               DWORD(data + 0x0C));
+                       break;
+
+               case 32: /* 7.33 System Boot Information */
+                       printf("System Boot Information\n");
+                       if (h->length < 0x0B) break;
+                       printf("\tStatus: %s\n",
+                               dmi_system_boot_status(data[0x0A]));
+                       break;
+
+               case 33: /* 7.34 64-bit Memory Error Information */
+                       if (h->length < 0x1F) break;
+                       printf("64-bit Memory Error Information\n");
+                       printf("\tType: %s\n",
+                               dmi_memory_error_type(data[0x04]));
+                       printf("\tGranularity: %s\n",
+                               dmi_memory_error_granularity(data[0x05]));
+                       printf("\tOperation: %s\n",
+                               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");
+                       break;
+
+               case 34: /* 7.35 Management Device */
+                       printf("Management Device\n");
+                       if (h->length < 0x0B) break;
+                       printf("\tDescription: %s\n",
+                               dmi_string(h, data[0x04]));
+                       printf("\tType: %s\n",
+                               dmi_management_device_type(data[0x05]));
+                       printf("\tAddress: 0x%08X\n",
+                               DWORD(data + 0x06));
+                       printf("\tAddress Type: %s\n",
+                               dmi_management_device_address_type(data[0x0A]));
+                       break;
+
+               case 35: /* 7.36 Management Device Component */
+                       printf("Management Device Component\n");
+                       if (h->length < 0x0B) break;
+                       printf("\tDescription: %s\n",
+                               dmi_string(h, data[0x04]));
+                       if (!(opt.flags & FLAG_QUIET))
+                       {
+                               printf("\tManagement Device Handle: 0x%04X\n",
+                                       WORD(data + 0x05));
+                               printf("\tComponent Handle: 0x%04X\n",
+                                       WORD(data + 0x07));
+                               if (WORD(data + 0x09) != 0xFFFF)
+                                       printf("\tThreshold Handle: 0x%04X\n",
+                                       WORD(data + 0x09));
+                       }
+                       break;
+
+               case 36: /* 7.37 Management Device Threshold Data */
+                       printf("Management Device Threshold Data\n");
+                       if (h->length < 0x10) break;
+                       if (WORD(data + 0x04) != 0x8000)
+                               printf("\tLower Non-critical Threshold: %d\n",
+                                       (i16)WORD(data + 0x04));
+                       if (WORD(data + 0x06) != 0x8000)
+                               printf("\tUpper Non-critical Threshold: %d\n",
+                                       (i16)WORD(data + 0x06));
+                       if (WORD(data + 0x08) != 0x8000)
+                               printf("\tLower Critical Threshold: %d\n",
+                                       (i16)WORD(data + 0x08));
+                       if (WORD(data + 0x0A) != 0x8000)
+                               printf("\tUpper Critical Threshold: %d\n",
+                                       (i16)WORD(data + 0x0A));
+                       if (WORD(data + 0x0C) != 0x8000)
+                               printf("\tLower Non-recoverable Threshold: %d\n",
+                                       (i16)WORD(data + 0x0C));
+                       if (WORD(data + 0x0E) != 0x8000)
+                               printf("\tUpper Non-recoverable Threshold: %d\n",
+                                       (i16)WORD(data + 0x0E));
+                       break;
+
+               case 37: /* 7.38 Memory Channel */
+                       printf("Memory Channel\n");
+                       if (h->length < 0x07) break;
+                       printf("\tType: %s\n",
+                               dmi_memory_channel_type(data[0x04]));
+                       printf("\tMaximal Load: %u\n",
+                               data[0x05]);
+                       printf("\tDevices: %u\n",
+                               data[0x06]);
+                       if (h->length < 0x07 + 3 * data[0x06]) break;
+                       dmi_memory_channel_devices(data[0x06], data + 0x07, "\t");
+                       break;
+
+               case 38: /* 7.39 IPMI Device Information */
+                       /*
+                        * We use the word "Version" instead of "Revision", conforming to
+                        * the IPMI specification.
+                        */
+                       printf("IPMI Device Information\n");
+                       if (h->length < 0x10) break;
+                       printf("\tInterface Type: %s\n",
+                               dmi_ipmi_interface_type(data[0x04]));
+                       printf("\tSpecification Version: %u.%u\n",
+                               data[0x05] >> 4, data[0x05] & 0x0F);
+                       printf("\tI2C Slave Address: 0x%02x\n",
+                               data[0x06] >> 1);
+                       if (data[0x07] != 0xFF)
+                               printf("\tNV Storage Device Address: %u\n",
+                                       data[0x07]);
+                       else
+                               printf("\tNV Storage Device: Not Present\n");
+                       printf("\tBase Address: ");
+                       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",
+                                       dmi_ipmi_register_spacing(data[0x10] >> 6));
+                               if (data[0x10] & (1 << 3))
+                               {
+                                       printf("\tInterrupt Polarity: %s\n",
+                                               data[0x10] & (1 << 1) ? "Active High" : "Active Low");
+                                       printf("\tInterrupt Trigger Mode: %s\n",
+                                               data[0x10] & (1 << 0) ? "Level" : "Edge");
+                               }
+                       }
+                       if (data[0x11] != 0x00)
+                       {
+                               printf("\tInterrupt Number: %x\n",
+                                       data[0x11]);
+                       }
+                       break;
+
+               case 39: /* 7.40 System Power Supply */
+                       printf("System Power Supply\n");
+                       if (h->length < 0x10) break;
+                       if (data[0x04] != 0x00)
+                               printf("\tPower Unit Group: %u\n",
+                                       data[0x04]);
+                       printf("\tLocation: %s\n",
+                               dmi_string(h, data[0x05]));
+                       printf("\tName: %s\n",
+                               dmi_string(h, data[0x06]));
+                       printf("\tManufacturer: %s\n",
+                               dmi_string(h, data[0x07]));
+                       printf("\tSerial Number: %s\n",
+                               dmi_string(h, data[0x08]));
+                       printf("\tAsset Tag: %s\n",
+                               dmi_string(h, data[0x09]));
+                       printf("\tModel Part Number: %s\n",
+                               dmi_string(h, data[0x0A]));
+                       printf("\tRevision: %s\n",
+                               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",
+                                       dmi_power_supply_status((WORD(data + 0x0E) >> 7) & 0x07));
+                       else
+                               printf(" Not Present");
+                       printf("\n");
+                       printf("\tType: %s\n",
+                               dmi_power_supply_type((WORD(data + 0x0E) >> 10) & 0x0F));
+                       printf("\tInput Voltage Range Switching: %s\n",
+                               dmi_power_supply_range_switching((WORD(data + 0x0E) >> 3) & 0x0F));
+                       printf("\tPlugged: %s\n",
+                               WORD(data + 0x0E) & (1 << 2) ? "No" : "Yes");
+                       printf("\tHot Replaceable: %s\n",
+                               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",
+                                               WORD(data + 0x10));
+                               if (WORD(data + 0x12) != 0xFFFF)
+                                       printf("\tCooling Device Handle: 0x%04X\n",
+                                               WORD(data + 0x12));
+                               if (WORD(data + 0x14) != 0xFFFF)
+                                       printf("\tInput Current Probe Handle: 0x%04X\n",
+                                               WORD(data + 0x14));
+                       }
+                       break;
+
+               case 40: /* 7.41 Additional Information */
+                       if (h->length < 0x0B) break;
+                       if (!(opt.flags & FLAG_QUIET))
+                               dmi_additional_info(h, "");
+                       break;
+
+               case 41: /* 7.42 Onboard Device Extended Information */
+                       printf("Onboard Device\n");
+                       if (h->length < 0x0B) break;
+                       printf("\tReference Designation: %s\n", dmi_string(h, data[0x04]));
+                       printf("\tType: %s\n",
+                               dmi_on_board_devices_type(data[0x05] & 0x7F));
+                       printf("\tStatus: %s\n",
+                               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");
+                       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 */
+                       {
+                               printf("\tVendor ID: 0x%02X%02X%02X%02X\n",
+                                       data[0x05], data[0x06], data[0x07],
+                                       data[0x08]);
+                       }
+                       break;
+
+               case 126: /* 7.44 Inactive */
+                       printf("Inactive\n");
+                       break;
+
+               case 127: /* 7.45 End Of Table */
+                       printf("End Of Table\n");
+                       break;
+
+               default:
+                       if (dmi_decode_oem(h))
+                               break;
+                       if (opt.flags & FLAG_QUIET)
+                               return;
+                       printf("%s Type\n",
+                               h->type >= 128 ? "OEM-specific" : "Unknown");
+                       dmi_dump(h, "\t");
+       }
+       printf("\n");
+}
+
+static void to_dmi_header(struct dmi_header *h, u8 *data)
+{
+       h->type = data[0];
+       h->length = data[1];
+       h->handle = WORD(data + 2);
+       h->data = data;
+}
+
+static void dmi_table_string(const struct dmi_header *h, const u8 *data, u16 ver)
+{
+       int key;
+       u8 offset = opt.string->offset;
+
+       if (offset >= h->length)
+               return;
+
+       key = (opt.string->type << 8) | offset;
+       switch (key)
+       {
+               case 0x108:
+                       dmi_system_uuid(data + offset, ver);
+                       printf("\n");
+                       break;
+               case 0x305:
+                       printf("%s\n", dmi_chassis_type(data[offset]));
+                       break;
+               case 0x406:
+                       printf("%s\n", dmi_processor_family(h, ver));
+                       break;
+               case 0x416:
+                       dmi_processor_frequency(data + offset);
+                       printf("\n");
+                       break;
+               default:
+                       printf("%s\n", dmi_string(h, data[offset]));
+       }
+}
+
+static void dmi_table_dump(u32 base, u16 len, const char *devmem)
+{
+       u8 *buf;
+
+       if ((buf = mem_chunk(base, len, devmem)) == NULL)
+       {
+               fprintf(stderr, "Failed to read table, sorry.\n");
+               return;
+       }
+
+       if (!(opt.flags & FLAG_QUIET))
+               printf("# Writing %d bytes to %s.\n", len, opt.dumpfile);
+       write_dump(32, len, buf, opt.dumpfile, 0);
+       free(buf);
+}
+
+static void dmi_table(u32 base, u16 len, u16 num, u16 ver, const char *devmem)
+{
+       u8 *buf;
+       u8 *data;
+       int i = 0;
+
+       if (ver > SUPPORTED_SMBIOS_VER)
+       {
+               printf("# SMBIOS implementations newer than version %u.%u are not\n"
+                      "# fully supported by this version of dmidecode.\n",
+                      SUPPORTED_SMBIOS_VER >> 8, SUPPORTED_SMBIOS_VER & 0xFF);
+       }
+
+       if (opt.flags & FLAG_DUMP_BIN)
+       {
+               dmi_table_dump(base, len, devmem);
+               return;
+       }
+
+       if (!(opt.flags & FLAG_QUIET))
+       {
+               if (opt.type == NULL)
+               {
+                       printf("%u structures occupying %u bytes.\n",
+                               num, len);
+                       if (!(opt.flags & FLAG_FROM_DUMP))
+                               printf("Table at 0x%08X.\n", base);
+               }
+               printf("\n");
+       }
+
+       if ((buf = mem_chunk(base, len, devmem)) == NULL)
+       {
+               fprintf(stderr, "Table is unreachable, sorry."
+#ifndef USE_MMAP
+                       " Try compiling dmidecode with -DUSE_MMAP."
+#endif
+                       "\n");
+               return;
+       }
+
+       data = buf;
+       while (i < num && data+4 <= buf + len) /* 4 is the length of an SMBIOS structure header */
+       {
+               u8 *next;
+               struct dmi_header h;
+               int display;
+
+               to_dmi_header(&h, data);
+               display = ((opt.type == NULL || opt.type[h.type])
+                       && !((opt.flags & FLAG_QUIET) && (h.type > 39 && h.type <= 127))
+                       && !opt.string);
+
+               /*
+                * If a short entry is found (less than 4 bytes), not only it
+                * is invalid, but we cannot reliably locate the next entry.
+                * Better stop at this point, and let the user know his/her
+                * table is broken.
+                */
+               if (h.length < 4)
+               {
+                       printf("Invalid entry length (%u). DMI table is "
+                              "broken! Stop.\n\n", (unsigned int)h.length);
+                       opt.flags |= FLAG_QUIET;
+                       break;
+               }
+
+               /* In quiet mode, stop decoding at end of table marker */
+               if ((opt.flags & FLAG_QUIET) && h.type == 127)
+                       break;
+
+               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 == 0 && h.length >= 5)
+                       dmi_set_vendor(dmi_string(&h, data[0x04]));
+
+               /* look for the next handle */
+               next = data + h.length;
+               while (next - buf + 1 < len && (next[0] != 0 || next[1] != 0))
+                       next++;
+               next += 2;
+               if (display)
+               {
+                       if (next - buf <= len)
+                       {
+                               if (opt.flags & FLAG_DUMP)
+                               {
+                                       dmi_dump(&h, "\t");
+                                       printf("\n");
+                               }
+                               else
+                                       dmi_decode(&h, ver);
+                       }
+                       else if (!(opt.flags & FLAG_QUIET))
+                               printf("\t<TRUNCATED>\n\n");
+               }
+               else if (opt.string != NULL
+                     && opt.string->type == h.type)
+                       dmi_table_string(&h, data, ver);
+
+               data = next;
+               i++;
+       }
+
+       if (!(opt.flags & FLAG_QUIET))
+       {
+               if (i != num)
+                       printf("Wrong DMI structures count: %d announced, "
+                               "only %d decoded.\n", num, i);
+               if (data - buf != len)
+                       printf("Wrong DMI structures length: %d bytes "
+                               "announced, structures occupy %d bytes.\n",
+                               len, (unsigned int)(data - buf));
+       }
+
+       free(buf);
+}
+
+
+/*
+ * Build a crafted entry point with table address hard-coded to 32,
+ * as this is where we will put it in the output file. We adjust the
+ * DMI checksum appropriately. The SMBIOS checksum needs no adjustment.
+ */
+static void overwrite_dmi_address(u8 *buf)
+{
+       buf[0x05] += buf[0x08] + buf[0x09] + buf[0x0A] + buf[0x0B] - 32;
+       buf[0x08] = 32;
+       buf[0x09] = 0;
+       buf[0x0A] = 0;
+       buf[0x0B] = 0;
+}
+
+static int smbios_decode(u8 *buf, const char *devmem)
+{
+       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)
+       {
+               case 0x021F:
+               case 0x0221:
+                       if (!(opt.flags & FLAG_QUIET))
+                               printf("SMBIOS version fixup (2.%d -> 2.%d).\n",
+                                      ver & 0xFF, 3);
+                       ver = 0x0203;
+                       break;
+               case 0x0233:
+                       if (!(opt.flags & FLAG_QUIET))
+                               printf("SMBIOS version fixup (2.%d -> 2.%d).\n",
+                                      51, 6);
+                       ver = 0x0206;
+                       break;
+       }
+       if (!(opt.flags & FLAG_QUIET))
+               printf("SMBIOS %u.%u present.\n",
+                       ver >> 8, ver & 0xFF);
+
+       dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C),
+               ver, devmem);
+
+       if (opt.flags & FLAG_DUMP_BIN)
+       {
+               u8 crafted[32];
+
+               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);
+       }
+
+       return 1;
+}
+
+static int legacy_decode(u8 *buf, const char *devmem)
+{
+       if (!checksum(buf, 0x0F))
+               return 0;
+
+       if (!(opt.flags & FLAG_QUIET))
+               printf("Legacy DMI %u.%u present.\n",
+                       buf[0x0E] >> 4, buf[0x0E] & 0x0F);
+
+       dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C),
+               ((buf[0x0E] & 0xF0) << 4) + (buf[0x0E] & 0x0F), devmem);
+
+       if (opt.flags & FLAG_DUMP_BIN)
+       {
+               u8 crafted[16];
+
+               memcpy(crafted, buf, 16);
+               overwrite_dmi_address(crafted);
+
+               printf("# Writing %d bytes to %s.\n", 0x0F, opt.dumpfile);
+               write_dump(0, 0x0F, crafted, opt.dumpfile, 1);
+       }
+
+       return 1;
+}
+
+/*
+ * Probe for EFI interface
+ */
+#define EFI_NOT_FOUND   (-1)
+#define EFI_NO_SMBIOS   (-2)
+static int address_from_efi(size_t *address)
+{
+       FILE *efi_systab;
+       const char *filename;
+       char linebuf[64];
+       int ret;
+
+       *address = 0; /* Prevent compiler warning */
+
+       /*
+        * Linux up to 2.6.6: /proc/efi/systab
+        * Linux 2.6.7 and up: /sys/firmware/efi/systab
+        */
+       if ((efi_systab = fopen(filename = "/sys/firmware/efi/systab", "r")) == NULL
+        && (efi_systab = fopen(filename = "/proc/efi/systab", "r")) == NULL)
+       {
+               /* No EFI interface, fallback to memory scan */
+               return EFI_NOT_FOUND;
+       }
+       ret = EFI_NO_SMBIOS;
+       while ((fgets(linebuf, sizeof(linebuf) - 1, efi_systab)) != NULL)
+       {
+               char *addrp = strchr(linebuf, '=');
+               *(addrp++) = '\0';
+               if (strcmp(linebuf, "SMBIOS") == 0)
+               {
+                       *address = strtoul(addrp, NULL, 0);
+                       if (!(opt.flags & FLAG_QUIET))
+                               printf("# SMBIOS entry point at 0x%08lx\n",
+                                      (unsigned long)*address);
+                       ret = 0;
+                       break;
+               }
+       }
+       if (fclose(efi_systab) != 0)
+               perror(filename);
+
+       if (ret == EFI_NO_SMBIOS)
+               fprintf(stderr, "%s: SMBIOS entry point missing\n", filename);
+       return ret;
+}
+
+int main(int argc, char * const argv[])
+{
+       int ret = 0;                /* Returned value */
+       int found = 0;
+       size_t fp;
+       int efi;
+       u8 *buf;
+
+       if (sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4 || '\0' != 0)
+       {
+               fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
+               exit(255);
+       }
+
+       /* Set default option values */
+       opt.devmem = DEFAULT_MEM_DEV;
+       opt.flags = 0;
+
+       if (parse_command_line(argc, argv)<0)
+       {
+               ret = 2;
+               goto exit_free;
+       }
+
+       if (opt.flags & FLAG_HELP)
+       {
+               print_help();
+               goto exit_free;
+       }
+
+       if (opt.flags & FLAG_VERSION)
+       {
+               printf("%s\n", VERSION);
+               goto exit_free;
+       }
+
+       if (!(opt.flags & FLAG_QUIET))
+               printf("# dmidecode %s\n", 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);
+               if ((buf = mem_chunk(0, 0x20, opt.dumpfile)) == NULL)
+               {
+                       ret = 1;
+                       goto exit_free;
+               }
+
+               if (memcmp(buf, "_SM_", 4) == 0)
+               {
+                       if (smbios_decode(buf, opt.dumpfile))
+                               found++;
+               }
+               else if (memcmp(buf, "_DMI_", 5) == 0)
+               {
+                       if (legacy_decode(buf, opt.dumpfile))
+                               found++;
+               }
+               goto done;
+       }
+
+       /* First try EFI (ia64, Intel-based Mac) */
+       efi = address_from_efi(&fp);
+       switch (efi)
+       {
+               case EFI_NOT_FOUND:
+                       goto memory_scan;
+               case EFI_NO_SMBIOS:
+                       ret = 1;
+                       goto exit_free;
+       }
+
+       if ((buf = mem_chunk(fp, 0x20, opt.devmem)) == NULL)
+       {
+               ret = 1;
+               goto exit_free;
+       }
+
+       if (smbios_decode(buf, opt.devmem))
+               found++;
+       goto done;
+
+memory_scan:
+       /* Fallback to memory scan (x86, x86_64) */
+       if ((buf = mem_chunk(0xF0000, 0x10000, opt.devmem)) == NULL)
+       {
+               ret = 1;
+               goto exit_free;
+       }
+
+       for (fp = 0; fp <= 0xFFF0; fp += 16)
+       {
+               if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0)
+               {
+                       if (smbios_decode(buf+fp, opt.devmem))
+                       {
+                               found++;
+                               fp += 16;
+                       }
+               }
+               else if (memcmp(buf + fp, "_DMI_", 5) == 0)
+               {
+                       if (legacy_decode(buf + fp, opt.devmem))
+                               found++;
+               }
+       }
+
+done:
+       if (!found && !(opt.flags & FLAG_QUIET))
+               printf("# No SMBIOS nor DMI entry point found, sorry.\n");
+
+       free(buf);
+exit_free:
+       free(opt.type);
+
+       return ret;
+}
diff --git a/dmidecode.h b/dmidecode.h
new file mode 100644 (file)
index 0000000..cae627b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the dmidecode project.
+ *
+ *   Copyright (C) 2005-2008 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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
+ */
+
+struct dmi_header
+{
+       u8 type;
+       u8 length;
+       u16 handle;
+       u8 *data;
+};
+
+const char *dmi_string(const struct dmi_header *dm, u8 s);
diff --git a/dmioem.c b/dmioem.c
new file mode 100644 (file)
index 0000000..2dd11c7
--- /dev/null
+++ b/dmioem.c
@@ -0,0 +1,129 @@
+/*
+ * Decoding of OEM-specific entries
+ * This file is part of the dmidecode project.
+ *
+ *   Copyright (C) 2007-2008 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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 <stdio.h>
+#include <string.h>
+
+#include "types.h"
+#include "dmidecode.h"
+#include "dmioem.h"
+
+/*
+ * Globals for vendor-specific decodes
+ */
+
+enum DMI_VENDORS { VENDOR_UNKNOWN, VENDOR_HP };
+
+static enum DMI_VENDORS dmi_vendor = VENDOR_UNKNOWN;
+
+/*
+ * 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)
+{
+       if (strcmp(s, "HP") == 0 || strcmp(s, "Hewlett-Packard") == 0)
+               dmi_vendor = VENDOR_HP;
+}
+
+/*
+ * HP-specific data structures are decoded here.
+ *
+ * Code contributed by John Cagle.
+ */
+
+static int dmi_decode_hp(const struct dmi_header *h)
+{
+       u8 *data = h->data;
+       int nic, ptr;
+
+       switch (h->type)
+       {
+               case 204:
+                       /*
+                        * Vendor Specific: HP ProLiant System/Rack Locator
+                        */
+                       printf("HP ProLiant System/Rack Locator\n");
+                       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]);
+                       break;
+
+               case 209:
+               case 221:
+                       /*
+                        * Vendor Specific: HP ProLiant NIC MAC Information
+                        *
+                        * This prints the BIOS NIC number,
+                        * PCI bus/device/function, and MAC address
+                        */
+                       printf(h->type == 221 ?
+                               "HP BIOS iSCSI NIC PCI and MAC Information\n" :
+                               "HP BIOS NIC PCI and MAC Information\n");
+                       nic = 1;
+                       ptr = 4;
+                       while (h->length >= ptr + 8)
+                       {
+                               if (data[ptr] == 0x00 && data[ptr + 1] == 0x00)
+                                       printf("\tNIC %d: Disabled\n", nic);
+                               else if (data[ptr] == 0xFF && data[ptr + 1] == 0xFF)
+                                       printf("\tNIC %d: Not Installed\n", nic);
+                               else
+                               {
+                                       printf("\tNIC %d: PCI device %02x:%02x.%x, "
+                                               "MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
+                                               nic, data[ptr + 1],
+                                               data[ptr] >> 3, data[ptr] & 7,
+                                               data[ptr + 2], data[ptr + 3],
+                                               data[ptr + 4], data[ptr + 5],
+                                               data[ptr + 6], data[ptr + 7]);
+                               }
+                               nic++;
+                               ptr += 8;
+                       }
+                       break;
+
+               default:
+                       return 0;
+       }
+       return 1;
+}
+
+/*
+ * Dispatch vendor-specific entries decoding
+ * Return 1 if decoding was successful, 0 otherwise
+ */
+int dmi_decode_oem(const struct dmi_header *h)
+{
+       switch (dmi_vendor)
+       {
+               case VENDOR_HP:
+                       return dmi_decode_hp(h);
+               default:
+                       return 0;
+       }
+}
diff --git a/dmioem.h b/dmioem.h
new file mode 100644 (file)
index 0000000..1c4971f
--- /dev/null
+++ b/dmioem.h
@@ -0,0 +1,25 @@
+/*
+ * Decoding of OEM-specific entries
+ * This file is part of the dmidecode project.
+ *
+ *   Copyright (C) 2007-2008 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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
+ */
+
+struct dmi_header;
+
+void dmi_set_vendor(const char *s);
+int dmi_decode_oem(const struct dmi_header *h);
diff --git a/dmiopt.c b/dmiopt.c
new file mode 100644 (file)
index 0000000..46e5cda
--- /dev/null
+++ b/dmiopt.c
@@ -0,0 +1,316 @@
+/*
+ * Command line handling of dmidecode
+ * This file is part of the dmidecode project.
+ *
+ *   Copyright (C) 2005-2008 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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 <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include "config.h"
+#include "types.h"
+#include "util.h"
+#include "dmidecode.h"
+#include "dmiopt.h"
+
+
+/* Options are global */
+struct opt opt;
+
+
+/*
+ * Handling of option --type
+ */
+
+struct type_keyword
+{
+       const char *keyword;
+       const u8 *type;
+};
+
+static const u8 opt_type_bios[] = { 0, 13, 255 };
+static const u8 opt_type_system[] = { 1, 12, 15, 23, 32, 255 };
+static const u8 opt_type_baseboard[] = { 2, 10, 41, 255 };
+static const u8 opt_type_chassis[] = { 3, 255 };
+static const u8 opt_type_processor[] = { 4, 255 };
+static const u8 opt_type_memory[] = { 5, 6, 16, 17, 255 };
+static const u8 opt_type_cache[] = { 7, 255 };
+static const u8 opt_type_connector[] = { 8, 255 };
+static const u8 opt_type_slot[] = { 9, 255 };
+
+static const struct type_keyword opt_type_keyword[] = {
+       { "bios", opt_type_bios },
+       { "system", opt_type_system },
+       { "baseboard", opt_type_baseboard },
+       { "chassis", opt_type_chassis },
+       { "processor", opt_type_processor },
+       { "memory", opt_type_memory },
+       { "cache", opt_type_cache },
+       { "connector", opt_type_connector },
+       { "slot", opt_type_slot },
+};
+
+static void print_opt_type_list(void)
+{
+       unsigned int i;
+
+       fprintf(stderr, "Valid type keywords are:\n");
+       for (i = 0; i < ARRAY_SIZE(opt_type_keyword); i++)
+       {
+               fprintf(stderr, "  %s\n", opt_type_keyword[i].keyword);
+       }
+}
+
+static u8 *parse_opt_type(u8 *p, const char *arg)
+{
+       unsigned int i;
+
+       /* Allocate memory on first call only */
+       if (p == NULL)
+       {
+               p = (u8 *)calloc(256, sizeof(u8));
+               if (p == NULL)
+               {
+                       perror("calloc");
+                       return NULL;
+               }
+       }
+
+       /* First try as a keyword */
+       for (i = 0; i < ARRAY_SIZE(opt_type_keyword); i++)
+       {
+               if (!strcasecmp(arg, opt_type_keyword[i].keyword))
+               {
+                       int j = 0;
+                       while (opt_type_keyword[i].type[j] != 255)
+                               p[opt_type_keyword[i].type[j++]] = 1;
+                       goto found;
+               }
+       }
+
+       /* Else try as a number */
+       while (*arg != '\0')
+       {
+               unsigned long val;
+               char *next;
+
+               val = strtoul(arg, &next, 0);
+               if (next == arg)
+               {
+                       fprintf(stderr, "Invalid type keyword: %s\n", arg);
+                       print_opt_type_list();
+                       goto exit_free;
+               }
+               if (val > 0xff)
+               {
+                       fprintf(stderr, "Invalid type number: %lu\n", val);
+                       goto exit_free;
+               }
+
+               p[val] = 1;
+               arg = next;
+               while (*arg == ',' || *arg == ' ')
+                       arg++;
+       }
+
+found:
+       return p;
+
+exit_free:
+       free(p);
+       return NULL;
+}
+
+
+/*
+ * Handling of option --string
+ */
+
+/* This lookup table could admittedly be reworked for improved performance.
+   Due to the low count of items in there at the moment, it did not seem
+   worth the additional code complexity though. */
+static const struct string_keyword opt_string_keyword[] = {
+       { "bios-vendor", 0, 0x04 },
+       { "bios-version", 0, 0x05 },
+       { "bios-release-date", 0, 0x08 },
+       { "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() */
+       { "baseboard-manufacturer", 2, 0x04 },
+       { "baseboard-product-name", 2, 0x05 },
+       { "baseboard-version", 2, 0x06 },
+       { "baseboard-serial-number", 2, 0x07 },
+       { "baseboard-asset-tag", 2, 0x08 },
+       { "chassis-manufacturer", 3, 0x04 },
+       { "chassis-type", 3, 0x05 },            /* dmi_chassis_type() */
+       { "chassis-version", 3, 0x06 },
+       { "chassis-serial-number", 3, 0x07 },
+       { "chassis-asset-tag", 3, 0x08 },
+       { "processor-family", 4, 0x06 },        /* dmi_processor_family() */
+       { "processor-manufacturer", 4, 0x07 },
+       { "processor-version", 4, 0x10 },
+       { "processor-frequency", 4, 0x16 },     /* dmi_processor_frequency() */
+};
+
+static void print_opt_string_list(void)
+{
+       unsigned int i;
+
+       fprintf(stderr, "Valid string keywords are:\n");
+       for (i = 0; i < ARRAY_SIZE(opt_string_keyword); i++)
+       {
+               fprintf(stderr, "  %s\n", opt_string_keyword[i].keyword);
+       }
+}
+
+static int parse_opt_string(const char *arg)
+{
+       unsigned int i;
+
+       if (opt.string)
+       {
+               fprintf(stderr, "Only one string can be specified\n");
+               return -1;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(opt_string_keyword); i++)
+       {
+               if (!strcasecmp(arg, opt_string_keyword[i].keyword))
+               {
+                       opt.string = &opt_string_keyword[i];
+                       return 0;
+               }
+       }
+
+       fprintf(stderr, "Invalid string keyword: %s\n", arg);
+       print_opt_string_list();
+       return -1;
+}
+
+
+/*
+ * Command line options handling
+ */
+
+/* Return -1 on error, 0 on success */
+int parse_command_line(int argc, char * const argv[])
+{
+       int option;
+       const char *optstring = "d:hqs:t:uV";
+       struct option longopts[] = {
+               { "dev-mem", required_argument, NULL, 'd' },
+               { "help", no_argument, NULL, 'h' },
+               { "quiet", 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' },
+               { "version", no_argument, NULL, 'V' },
+               { 0, 0, 0, 0 }
+       };
+
+       while ((option = getopt_long(argc, argv, optstring, longopts, NULL)) != -1)
+               switch (option)
+               {
+                       case 'B':
+                               opt.flags |= FLAG_DUMP_BIN;
+                               opt.dumpfile = optarg;
+                               break;
+                       case 'F':
+                               opt.flags |= FLAG_FROM_DUMP;
+                               opt.dumpfile = optarg;
+                               break;
+                       case 'd':
+                               opt.devmem = optarg;
+                               break;
+                       case 'h':
+                               opt.flags |= FLAG_HELP;
+                               break;
+                       case 'q':
+                               opt.flags |= FLAG_QUIET;
+                               break;
+                       case 's':
+                               if (parse_opt_string(optarg) < 0)
+                                       return -1;
+                               opt.flags |= FLAG_QUIET;
+                               break;
+                       case 't':
+                               opt.type = parse_opt_type(opt.type, optarg);
+                               if (opt.type == NULL)
+                                       return -1;
+                               break;
+                       case 'u':
+                               opt.flags |= FLAG_DUMP;
+                               break;
+                       case 'V':
+                               opt.flags |= FLAG_VERSION;
+                               break;
+                       case '?':
+                               switch (optopt)
+                               {
+                                       case 's':
+                                               fprintf(stderr, "String keyword expected\n");
+                                               print_opt_string_list();
+                                               break;
+                                       case 't':
+                                               fprintf(stderr, "Type number or keyword expected\n");
+                                               print_opt_type_list();
+                                               break;
+                               }
+                               return -1;
+               }
+
+       /* Check for mutually exclusive output format options */
+       if ((opt.string != NULL) + (opt.type != NULL)
+         + !!(opt.flags & FLAG_DUMP_BIN) > 1)
+       {
+               fprintf(stderr, "Options --string, --type and --dump-bin are mutually exclusive\n");
+               return -1;
+       }
+
+       if ((opt.flags & FLAG_FROM_DUMP) && (opt.flags & FLAG_DUMP_BIN))
+       {
+               fprintf(stderr, "Options --from-dump and --dump-bin are mutually exclusive\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+void print_help(void)
+{
+       static const char *help =
+               "Usage: dmidecode [OPTIONS]\n"
+               "Options are:\n"
+               " -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"
+               " -s, --string KEYWORD   Only display the value of the given DMI string\n"
+               " -t, --type TYPE        Only display the entries of given type\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"
+               " -V, --version          Display the version and exit\n";
+
+       printf("%s", help);
+}
diff --git a/dmiopt.h b/dmiopt.h
new file mode 100644 (file)
index 0000000..17f1849
--- /dev/null
+++ b/dmiopt.h
@@ -0,0 +1,47 @@
+/*
+ * Command line handling of dmidecode
+ * This file is part of the dmidecode project.
+ *
+ *   Copyright (C) 2005-2008 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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
+ */
+
+struct string_keyword
+{
+       const char *keyword;
+       u8 type;
+       u8 offset;
+};
+
+struct opt
+{
+       const char *devmem;
+       unsigned int flags;
+       u8 *type;
+       const struct string_keyword *string;
+       char *dumpfile;
+};
+extern struct opt opt;
+
+#define FLAG_VERSION            (1 << 0)
+#define FLAG_HELP               (1 << 1)
+#define FLAG_DUMP               (1 << 2)
+#define FLAG_QUIET              (1 << 3)
+#define FLAG_DUMP_BIN           (1 << 4)
+#define FLAG_FROM_DUMP          (1 << 5)
+
+int parse_command_line(int argc, char * const argv[]);
+void print_help(void);
diff --git a/man/biosdecode.8 b/man/biosdecode.8
new file mode 100644 (file)
index 0000000..46bea95
--- /dev/null
@@ -0,0 +1,83 @@
+.TH BIOSDECODE 8 "February 2007" "dmidecode"
+.SH NAME
+biosdecode \- \s-1BIOS\s0 information decoder
+.SH SYNOPSIS
+.B biosdecode
+.RB [ OPTIONS ]
+
+.SH DESCRIPTION
+.B biosdecode
+parses the \s-1BIOS\s0 memory and prints information about all structures (or
+entry points) it knows of. Currently known entry point types are:
+.IP \(bu "\w'\(bu'u+1n"
+\s-1SMBIOS\s0 (System Management \s-1BIOS\s0)
+.br
+Use
+.B dmidecode
+for a more detailed output.
+.IP \(bu
+\s-1DMI\s0 (Desktop Management Interface, a legacy version of \s-1SMBIOS\s0)
+.br
+Use
+.B dmidecode
+for a more detailed output.
+.IP \(bu
+\s-1SYSID\s0
+.IP \(bu
+\s-1PNP\s0 (Plug and Play)
+.IP \(bu
+\s-1ACPI\s0 (Advanced Configuration and Power Interface)
+.IP \(bu
+\s-1BIOS32\s0 (\s-1BIOS32\s0 Service Directory)
+.IP \(bu
+\s-1PIR\s0 (\s-1PCI\s0 \s-1IRQ\s0 Routing)
+.IP \(bu
+\s-132OS\s0 (\s-1BIOS32\s0 Extension, Compaq-specific)
+.br
+See
+.B ownership
+for a Compaq ownership tag retrieval tool.
+.IP \(bu
+\s-1SNY\s0 (Sony-specific, not decoded)
+.IP \(bu
+\s-1VPD\s0 (Vital Product Data, IBM-specific)
+.br
+Use
+.B vpddecode
+for a more detailed output.
+.IP \(bu
+\s-1FJKEYINF\s0 (Application Panel, Fujitsu-specific)
+
+.PP
+.B biosdecode
+started its life as a part of
+.B dmidecode
+but as more entry point types were added, if 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)
+.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),
+.BR ownership (8),
+.BR vpddecode (8)
diff --git a/man/dmidecode.8 b/man/dmidecode.8
new file mode 100644 (file)
index 0000000..164dffa
--- /dev/null
@@ -0,0 +1,238 @@
+.TH DMIDECODE 8 "November 2008" "dmidecode"
+.SH NAME
+dmidecode \- \s-1DMI\s0 table decoder
+.SH SYNOPSIS
+.B dmidecode
+.RB [ OPTIONS ]
+
+.SH DESCRIPTION
+.B dmidecode
+is a tool for dumping a computer's \s-1DMI\s0 (some say \s-1SMBIOS\s0) table
+contents in a human-readable format. This table contains a description of the
+system's hardware components, as well as other useful pieces of information
+such as serial numbers and \s-1BIOS\s0 revision. Thanks to this table, you can
+retrieve this information without having to probe for the actual hardware.
+While this is a good point in terms of report speed and safeness, this also
+makes the presented information possibly unreliable.
+
+The \s-1DMI\s0 table doesn't only describe what the system is currently made
+of, it also can report the possible evolutions (such as the fastest supported
+\s-1CPU\s0 or the maximal amount of memory supported).
+
+\s-1SMBIOS\s0 stands for System Management \s-1BIOS\s0, while \s-1DMI\s0
+stands for Desktop Management Interface. Both standards are tightly related
+and developed by the \s-1DMTF\s0 (Desktop Management Task Force).
+
+As you run it,
+.B dmidecode
+will try to locate the \s-1DMI\s0 table. If it succeeds, it will then parse
+this table and display a list of records like this one:
+
+Handle 0x0002, DMI type 2, 8 bytes.
+Base Board Information
+        Manufacturer: Intel
+        Product Name: C440GX+
+        Version: 727281-001
+        Serial Number: INCY92700942
+
+Each record has:
+.IP \(bu "\w'\(bu'u+1n"
+A handle. This is a unique identifier, which allows records to
+reference each other. For example, processor records usually reference
+cache memory records using their handles.
+.IP \(bu
+A type. The \s-1SMBIOS\s0 specification defines different types of elements
+a computer can be made of. In this example, the type is 2, which
+means that the record contains "Base Board Information".
+.IP \(bu
+A size. Each record has a 4-byte header (2 for the handle, 1 for the type,
+1 for the size), the rest is used by the record data. This value doesn't
+take text strings into account (these are placed at the end of the record),
+so the actual length of the record may be (and is often) greater than the
+displayed value.
+.IP \(bu
+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)
+.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.
+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
+keywords is printed and
+.B dmidecode
+exits with an error.
+This option cannot be used more than once.
+.TP
+.BR "-t" ", " "--type TYPE"
+Only display the entries of type \fBTYPE\fR. \fBTYPE\fR 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.
+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
+is printed and
+.B dmidecode
+exits with an error.
+.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"
+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
+later.
+.TP
+.BR "  " "  " "--from-dump FILE"
+Read the DMI data from a binary file previously generated using 
+\fB--dump-bin\fR.
+.TP
+.BR "-h" ", " "--help"
+Display usage information and exit
+.TP
+.BR "-V" ", " "--version"
+Display the version and exit
+.P
+Options --string, --type and --dump-bin
+determine the output format and are mutually exclusive.
+
+.SH "DMI TYPES"
+The \s-1SMBIOS\s0 specification defines the following \s-1DMI\s0 types:
+
+.TS
+r l
+__
+r l.
+Type   Information
+0      BIOS
+1      System
+2      Base Board
+3      Chassis
+4      Processor
+5      Memory Controller
+6      Memory Module
+7      Cache
+8      Port Connector
+9      System Slots
+10     On Board Devices
+11     OEM Strings
+12     System Configuration Options
+13     BIOS Language
+14     Group Associations
+15     System Event Log
+16     Physical Memory Array
+17     Memory Device
+18     32-bit Memory Error
+19     Memory Array Mapped Address
+20     Memory Device Mapped Address
+21     Built-in Pointing Device
+22     Portable Battery
+23     System Reset
+24     Hardware Security
+25     System Power Controls
+26     Voltage Probe
+27     Cooling Device
+28     Temperature Probe
+29     Electrical Current Probe
+30     Out-of-band Remote Access
+31     Boot Integrity Services
+32     System Boot
+33     64-bit Memory Error
+34     Management Device
+35     Management Device Component
+36     Management Device Threshold Data
+37     Memory Channel
+38     IPMI Device
+39     Power Supply
+40     Additional Information
+41     Onboard Device
+.TE
+
+Additionally, type 126 is used for disabled entries and type 127 is an
+end-of-table marker. Types 128 to 255 are for \s-1OEM\s0-specific data.
+.B dmidecode
+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.
+Each keyword is equivalent to a list of type numbers:
+
+.TS
+l l
+__
+l l.
+Keyword        Types
+bios   0, 13
+system 1, 12, 15, 23, 32
+baseboard      2, 10, 41
+chassis        3
+processor      4
+memory 5, 6, 16, 17
+cache  7
+connector      8
+slot   9
+.TE
+
+Keywords are matched case-insensitively. The following command lines are equivalent:
+.IP \(bu "\w'\(bu'u+1n"
+dmidecode --type 0 --type 13
+.IP \(bu
+dmidecode --type 0,13
+.IP \(bu
+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
+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 FILES
+.I /dev/mem
+.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),
+.BR ownership (8),
+.BR vpddecode (8)
diff --git a/man/ownership.8 b/man/ownership.8
new file mode 100644 (file)
index 0000000..f24ef94
--- /dev/null
@@ -0,0 +1,37 @@
+.TH OWNERSHIP 8 "February 2005" "dmidecode"
+.SH NAME
+ownership \- Compaq ownership tag retriever
+.SH SYNOPSIS
+.B ownership
+.RB [ OPTIONS ]
+
+.SH DESCRIPTION
+.B ownership
+retrieves and prints the "ownership tag" that can be set on Compaq
+computers. Contrary to all other programs of the
+.B dmidecode
+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)
+.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),
+.BR mem (4),
+.BR vpddecode (8)
diff --git a/man/vpddecode.8 b/man/vpddecode.8
new file mode 100644 (file)
index 0000000..c9e4acf
--- /dev/null
@@ -0,0 +1,74 @@
+.TH VPDDECODE 8 "February 2007" "dmidecode"
+.SH NAME
+vpddecode \- \s-1VPD\s0 structure decoder
+.SH SYNOPSIS
+.B vpddecode
+.RB [ OPTIONS ]
+
+.SH DESCRIPTION
+.B vpddecode
+prints the "vital product data" information that can be found in almost
+all IBM and Lenovo computers. Available items are:
+.IP \(bu "\w'\(bu'u+1n"
+\s-1BIOS\s0 Build \s-1ID\s0
+.IP \(bu
+Box Serial Number
+.IP \(bu
+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)
+.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.
+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
+keywords is printed and
+.B vpddecode
+exits with an error.
+This option cannot be used more than once.
+Mutually exclusive with \fB--dump\fR.
+.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.
+.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),
+.BR mem (4),
+.BR ownership (8)
diff --git a/ownership.c b/ownership.c
new file mode 100644 (file)
index 0000000..d79af12
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Compaq Ownership Tag
+ *
+ *   Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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
+ *
+ *   For the avoidance of doubt the "preferred form" of this code is one which
+ *   is in an open unpatent encumbered format. Where cryptographic key signing
+ *   forms part of the process of creating an executable the information
+ *   including keys needed to generate an equivalently functional executable
+ *   are deemed to be part of the source code.
+ *
+ * References:
+ *  - Compaq "Technical Reference Guide for Compaq Deskpro 4000 and 6000"
+ *    First Edition
+ *    http://h18000.www1.hp.com/support/techpubs/technical_reference_guides/113a1097.html
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "version.h"
+#include "config.h"
+#include "types.h"
+#include "util.h"
+
+/* Options are global */
+struct opt
+{
+       const char *devmem;
+       unsigned int flags;
+};
+static struct opt opt;
+
+#define FLAG_VERSION            (1 << 0)
+#define FLAG_HELP               (1 << 1)
+
+static void ownership(u32 base, const char *pname, const char *devmem)
+{
+       u8 *buf;
+       int i;
+
+       /* read the ownership tag */
+       if ((buf = mem_chunk(base, 0x51, devmem)) == NULL)
+       {
+               perror(pname);
+               return;
+       }
+
+       /* chop the trailing garbage */
+       i = 0x4f;
+       while (i >= 0 && (buf[i] == 0x20 || buf[i] == 0x00))
+               i--;
+       buf[i + 1] = '\0';
+
+       /* filter and print */
+       if (i >= 0)
+       {
+               for (; i >= 0; i--)
+               {
+                       if (buf[i] < 32 || (buf[i] >= 127 && buf[i] < 160))
+                               buf[i] = '?';
+               }
+               printf("%s\n", (char *)buf);
+       }
+
+       free(buf);
+}
+
+static u32 decode(const u8 *p)
+{
+       int i;
+
+       /* integrity checking (lack of checksum) */
+       for (i = 0; i < p[4]; i++)
+       {
+               if (p[5 + i * 10] != '$'
+                || !(p[6 + i * 10] >= 'A' && p[6 + i * 10] <= 'Z')
+                || !(p[7 + i * 10] >= 'A' && p[7 + i * 10] <= 'Z')
+                || !(p[8 + i * 10] >= 'A' && p[8 + i * 10] <= 'Z'))
+               {
+                       printf("\t Abnormal Entry! Please report. [%02x %02x %02x %02x]\n",
+                               p[5 + i * 10], p[6 + i * 10],
+                               p[7 + i * 10], p[8 + i * 10]);
+                       return 0;
+               }
+       }
+
+       /* search for the right entry */
+       for (i = 0; i < p[4]; i++)
+               if (memcmp(p + 5 + i * 10, "$ERB", 4) == 0)
+                       return DWORD(p + 9 + i * 10);
+
+       return 0;
+}
+
+/* Return -1 on error, 0 on success */
+static int parse_command_line(int argc, char * const argv[])
+{
+       int option;
+       const char *optstring = "d:hV";
+       struct option longopts[] = {
+               { "dev-mem", required_argument, NULL, 'd' },
+               { "help", no_argument, NULL, 'h' },
+               { "version", no_argument, NULL, 'V' },
+               { 0, 0, 0, 0 }
+       };
+
+       while ((option = getopt_long(argc, argv, optstring, longopts, NULL)) != -1)
+               switch (option)
+               {
+                       case 'd':
+                               opt.devmem = optarg;
+                               break;
+                       case 'h':
+                               opt.flags |= FLAG_HELP;
+                               break;
+                       case 'V':
+                               opt.flags |= FLAG_VERSION;
+                               break;
+                       case '?':
+                               return -1;
+               }
+
+       return 0;
+}
+
+static void print_help(void)
+{
+       static const char *help =
+               "Usage: ownership [OPTIONS]\n"
+               "Options are:\n"
+               " -d, --dev-mem FILE     Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n"
+               " -h, --help             Display this help text and exit\n"
+               " -V, --version          Display the version and exit\n";
+
+       printf("%s", help);
+}
+
+int main(int argc, char * const argv[])
+{
+       u8 *buf;
+       off_t fp;
+       int ok = 0;
+
+       if (sizeof(u8) != 1 || sizeof(u32) != 4)
+       {
+               fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
+               exit(255);
+       }
+
+       /* Set default option values */
+       opt.devmem = DEFAULT_MEM_DEV;
+       opt.flags = 0;
+
+       if (parse_command_line(argc, argv)<0)
+               exit(2);
+
+       if (opt.flags & FLAG_HELP)
+       {
+               print_help();
+               return 0;
+       }
+
+       if (opt.flags & FLAG_VERSION)
+       {
+               printf("%s\n", VERSION);
+               return 0;
+       }
+
+       if ((buf = mem_chunk(0xE0000, 0x20000, opt.devmem)) == NULL)
+               exit(1);
+
+       for (fp = 0; !ok && fp <= 0x1FFF0; fp += 16)
+       {
+               u8 *p = buf + fp;
+
+               if (memcmp((char *)p, "32OS", 4) == 0)
+               {
+                       off_t len = p[4] * 10 + 5;
+
+                       if (fp + len - 1 <= 0x1FFFF)
+                       {
+                               u32 base;
+
+                               if ((base = decode(p)))
+                               {
+                                       ok = 1;
+                                       ownership(base, argv[0], opt.devmem);
+                               }
+                       }
+               }
+       }
+
+       free(buf);
+
+       return 0;
+}
diff --git a/types.h b/types.h
new file mode 100644 (file)
index 0000000..19d803d
--- /dev/null
+++ b/types.h
@@ -0,0 +1,62 @@
+#ifndef TYPES_H
+#define TYPES_H
+
+#include "config.h"
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef signed short i16;
+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 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
+ *   for architectures which need it.
+ */
+
+#ifdef BIGENDIAN
+typedef struct {
+       u32 h;
+       u32 l;
+} u64;
+#else
+typedef struct {
+       u32 l;
+       u32 h;
+} u64;
+#endif
+
+#ifdef ALIGNMENT_WORKAROUND
+static inline u64 U64(u32 low, u32 high)
+{
+       u64 self;
+
+       self.l = low;
+       self.h = high;
+
+       return self;
+}
+#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 */
+#define WORD(x) (u16)(*(const u16 *)(x))
+#define DWORD(x) (u32)(*(const u32 *)(x))
+#define QWORD(x) (*(const u64 *)(x))
+#endif /* ALIGNMENT_WORKAROUND */
+
+#endif
diff --git a/util.c b/util.c
new file mode 100644 (file)
index 0000000..afddd45
--- /dev/null
+++ b/util.c
@@ -0,0 +1,219 @@
+/*
+ * Common "util" functions
+ * This file is part of the dmidecode project.
+ *
+ *   Copyright (C) 2002-2010 Jean Delvare <khali@linux-fr>
+ *
+ *   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
+ *
+ *   For the avoidance of doubt the "preferred form" of this code is one which
+ *   is in an open unpatent encumbered format. Where cryptographic key signing
+ *   forms part of the process of creating an executable the information
+ *   including keys needed to generate an equivalently functional executable
+ *   are deemed to be part of the source code.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "config.h"
+
+#ifdef USE_MMAP
+#include <sys/mman.h>
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *) -1)
+#endif /* !MAP_FAILED */
+#endif /* USE MMAP */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "types.h"
+#include "util.h"
+
+static int myread(int fd, u8 *buf, size_t count, const char *prefix)
+{
+       ssize_t r = 1;
+       size_t r2 = 0;
+
+       while (r2 != count && r != 0)
+       {
+               r = read(fd, buf + r2, count - r2);
+               if (r == -1)
+               {
+                       if (errno != EINTR)
+                       {
+                               close(fd);
+                               perror(prefix);
+                               return -1;
+                       }
+               }
+               else
+                       r2 += r;
+       }
+
+       if (r2 != count)
+       {
+               close(fd);
+               fprintf(stderr, "%s: Unexpected end of file\n", prefix);
+               return -1;
+       }
+
+       return 0;
+}
+
+int checksum(const u8 *buf, size_t len)
+{
+       u8 sum = 0;
+       size_t a;
+
+       for (a = 0; a < len; a++)
+               sum += buf[a];
+       return (sum == 0);
+}
+
+/*
+ * Copy a physical memory chunk into a memory buffer.
+ * This function allocates memory.
+ */
+void *mem_chunk(size_t base, size_t len, const char *devmem)
+{
+       void *p;
+       int fd;
+#ifdef USE_MMAP
+       size_t mmoffset;
+       void *mmp;
+#endif
+
+       if ((fd = open(devmem, O_RDONLY)) == -1)
+       {
+               perror(devmem);
+               return NULL;
+       }
+
+       if ((p = malloc(len)) == NULL)
+       {
+               perror("malloc");
+               return NULL;
+       }
+
+#ifdef USE_MMAP
+#ifdef _SC_PAGESIZE
+       mmoffset = base % sysconf(_SC_PAGESIZE);
+#else
+       mmoffset = base % getpagesize();
+#endif /* _SC_PAGESIZE */
+       /*
+        * Please note that we don't use mmap() for performance reasons here,
+        * but to workaround problems many people encountered when trying
+        * to read from /dev/mem using regular read() calls.
+        */
+       mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset);
+       if (mmp == MAP_FAILED)
+               goto try_read;
+
+       memcpy(p, (u8 *)mmp + mmoffset, len);
+
+       if (munmap(mmp, mmoffset + len) == -1)
+       {
+               fprintf(stderr, "%s: ", devmem);
+               perror("munmap");
+       }
+
+       goto out;
+
+#endif /* USE_MMAP */
+
+try_read:
+       if (lseek(fd, base, SEEK_SET) == -1)
+       {
+               fprintf(stderr, "%s: ", devmem);
+               perror("lseek");
+               free(p);
+               return NULL;
+       }
+
+       if (myread(fd, p, len, devmem) == -1)
+       {
+               free(p);
+               return NULL;
+       }
+
+out:
+       if (close(fd) == -1)
+               perror(devmem);
+
+       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)
+{
+       u64 res;
+
+       res.h = end.h - start.h;
+       res.l = end.l - start.l;
+
+       if (end.l < start.l)
+               res.h--;
+       if (++res.l == 0)
+               res.h++;
+
+       return res;
+}
diff --git a/util.h b/util.h
new file mode 100644 (file)
index 0000000..d4c3196
--- /dev/null
+++ b/util.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the dmidecode project.
+ *
+ *   Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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 <sys/types.h>
+
+#include "types.h"
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+int checksum(const u8 *buf, size_t len);
+void *mem_chunk(size_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
new file mode 100644 (file)
index 0000000..1641a63
--- /dev/null
+++ b/version.h
@@ -0,0 +1 @@
+#define VERSION "2.11"
diff --git a/vpddecode.c b/vpddecode.c
new file mode 100644 (file)
index 0000000..2b0d27c
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * IBM Vital Product Data decoder
+ *
+ *   Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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
+ *
+ *   For the avoidance of doubt the "preferred form" of this code is one which
+ *   is in an open unpatent encumbered format. Where cryptographic key signing
+ *   forms part of the process of creating an executable the information
+ *   including keys needed to generate an equivalently functional executable
+ *   are deemed to be part of the source code.
+ *
+ * References:
+ *  - IBM "Using the BIOS Build ID to identify Thinkpad systems"
+ *    Revision 2006-01-31
+ *    http://www-307.ibm.com/pc/support/site.wss/MIGR-45120.html
+ *
+ * Notes:
+ *  - Main part of the code is taken directly from biosdecode, with an
+ *    additional command line interface and a few experimental features.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "version.h"
+#include "config.h"
+#include "types.h"
+#include "util.h"
+#include "vpdopt.h"
+
+static void print_entry(const char *name, const u8 *p, size_t len)
+{
+       size_t i;
+
+       if (name != NULL)
+               printf("%s: ", name);
+       for (i = 0; i < len; i++)
+       {
+               /* ASCII filtering */
+               if (p[i] >= 32 && p[i] < 127)
+                       printf("%c", p[i]);
+               else if (p[i] != 0)
+                       printf(".");
+       }
+       printf("\n");
+}
+
+static void dump(const u8 *p, u8 len)
+{
+       int done, i, min;
+
+       for (done = 0; done < len; done += 16)
+       {
+               printf("%02X:", done);
+               min = (len - done < 16) ? len - done : 16;
+
+               /* As hexadecimal first */
+               for (i = 0; i < min; i++)
+                       printf(" %02X", p[done + i]);
+               for (; i < 16; i++) /* Complete line if needed */
+                       printf("   ");
+               printf("     ");
+
+               /* And now as text, with ASCII filtering */
+               for (i = 0; i < min; i++)
+                       printf("%c", (p[done + i] >= 32 && p[done + i] < 127) ?
+                               p[done + i] : '.');
+               printf("\n");
+       }
+}
+
+static int decode(const u8 *p)
+{
+       if (p[5] < 0x30)
+               return 0;
+
+       /* XSeries have longer records, exact length seems to vary. */
+       if (!(p[5] >= 0x45 && checksum(p, p[5]))
+       /* Some Netvista seem to work with this. */
+        && !(checksum(p, 0x30))
+       /* The Thinkpad/Thinkcentre checksum does *not* include the first
+          13 bytes. */
+        && !(checksum(p + 0x0D, 0x30 - 0x0D)))
+       {
+               /* A few systems have a bad checksum (xSeries 325, 330, 335
+                  and 345 with early BIOS) but the record is otherwise
+                  valid. */
+               if (!(opt.flags & FLAG_QUIET))
+                       printf("# Bad checksum!\n");
+       }
+
+       if (opt.string != NULL)
+       {
+               if (opt.string->offset + opt.string->len < p[5])
+                       print_entry(NULL, p + opt.string->offset,
+                                   opt.string->len);
+               return 1;
+       }
+
+       print_entry("BIOS Build ID", p + 0x0D, 9);
+       print_entry("Box Serial Number", p + 0x16, 7);
+       print_entry("Motherboard Serial Number", p + 0x1D, 11);
+       print_entry("Machine Type/Model", p + 0x28, 7);
+
+       if (p[5] < 0x44)
+               return 1;
+
+       print_entry("BIOS Release Date", p + 0x30, 8);
+       print_entry("Default Flash Image File Name", p + 0x38, 12);
+
+       if (p[5] >= 0x46 && p[0x44] != 0x00)
+       {
+               printf("%s: %u\n", "BIOS Revision", p[0x44]);
+       }
+
+       return 1;
+}
+
+int main(int argc, char * const argv[])
+{
+       u8 *buf;
+       int found = 0;
+       unsigned int fp;
+
+       if (sizeof(u8) != 1)
+       {
+               fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
+               exit(255);
+       }
+
+       /* Set default option values */
+       opt.devmem = DEFAULT_MEM_DEV;
+       opt.flags = 0;
+
+       if (parse_command_line(argc, argv)<0)
+               exit(2);
+
+       if (opt.flags & FLAG_HELP)
+       {
+               print_help();
+               return 0;
+       }
+
+       if (opt.flags & FLAG_VERSION)
+       {
+               printf("%s\n", VERSION);
+               return 0;
+       }
+
+       if (!(opt.flags & FLAG_QUIET))
+               printf("# vpddecode %s\n", VERSION);
+
+       if ((buf = mem_chunk(0xF0000, 0x10000, opt.devmem)) == NULL)
+               exit(1);
+
+       for (fp = 0; fp <= 0xFFF0; fp += 4)
+       {
+               u8 *p = buf + fp;
+
+               if (memcmp((char *)p, "\252\125VPD", 5) == 0
+                && fp + p[5] - 1 <= 0xFFFF)
+               {
+                       if (fp % 16 && !(opt.flags & FLAG_QUIET))
+                               printf("# Unaligned address (%#x)\n",
+                                      0xf0000 + fp);
+                       if (opt.flags & FLAG_DUMP)
+                       {
+                               dump(p, p[5]);
+                               found++;
+                       }
+                       else
+                       {
+                               if (decode(p))
+                                       found++;
+                       }
+               }
+       }
+
+       free(buf);
+
+       if (!found && !(opt.flags & FLAG_QUIET))
+               printf("# No VPD structure found, sorry.\n");
+
+       return 0;
+}
diff --git a/vpdopt.c b/vpdopt.c
new file mode 100644 (file)
index 0000000..021ade2
--- /dev/null
+++ b/vpdopt.c
@@ -0,0 +1,157 @@
+/*
+ * Command line handling of vpddecode
+ * This file is part of the dmidecode project.
+ *
+ *   Copyright (C) 2005-2007 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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 <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include "config.h"
+#include "util.h"
+#include "vpdopt.h"
+
+
+/* Options are global */
+struct opt opt;
+
+
+/*
+ * Handling of option --string
+ */
+
+/* This lookup table could admittedly be reworked for improved performance.
+   Due to the low count of items in there at the moment, it did not seem
+   worth the additional code complexity though. */
+static const struct string_keyword opt_string_keyword[] = {
+       { "bios-build-id", 0x0D, 9 },
+       { "box-serial-number", 0x16, 7 },
+       { "motherboard-serial-number", 0x1D, 11 },
+       { "machine-type-model", 0x28, 7 },
+       { "bios-release-date", 0x30, 8 },
+};
+
+static void print_opt_string_list(void)
+{
+       unsigned int i;
+
+       fprintf(stderr, "Valid string keywords are:\n");
+       for (i = 0; i < ARRAY_SIZE(opt_string_keyword); i++)
+       {
+               fprintf(stderr, "  %s\n", opt_string_keyword[i].keyword);
+       }
+}
+
+static int parse_opt_string(const char *arg)
+{
+       unsigned int i;
+
+       if (opt.string)
+       {
+               fprintf(stderr, "Only one string can be specified\n");
+               return -1;
+       }
+
+       for (i = 0; i<ARRAY_SIZE(opt_string_keyword); i++)
+       {
+               if (!strcasecmp(arg, opt_string_keyword[i].keyword))
+               {
+                       opt.string = &opt_string_keyword[i];
+                       return 0;
+               }
+       }
+
+       fprintf(stderr, "Invalid string keyword: %s\n", arg);
+       print_opt_string_list();
+       return -1;
+}
+
+
+/*
+ * Command line options handling
+ */
+
+/* Return -1 on error, 0 on success */
+int parse_command_line(int argc, char * const argv[])
+{
+       int option;
+       const char *optstring = "d:hs:uV";
+       struct option longopts[] = {
+               { "dev-mem", required_argument, NULL, 'd' },
+               { "help", no_argument, NULL, 'h' },
+               { "string", required_argument, NULL, 's' },
+               { "dump", no_argument, NULL, 'u' },
+               { "version", no_argument, NULL, 'V' },
+               { 0, 0, 0, 0 }
+       };
+
+       while ((option = getopt_long(argc, argv, optstring, longopts, NULL)) != -1)
+               switch (option)
+               {
+                       case 'd':
+                               opt.devmem = optarg;
+                               break;
+                       case 'h':
+                               opt.flags |= FLAG_HELP;
+                               break;
+                       case 's':
+                               if (parse_opt_string(optarg) < 0)
+                                       return -1;
+                               opt.flags |= FLAG_QUIET;
+                               break;
+                       case 'u':
+                               opt.flags |= FLAG_DUMP;
+                               break;
+                       case 'V':
+                               opt.flags |= FLAG_VERSION;
+                               break;
+                       case '?':
+                               switch (optopt)
+                               {
+                                       case 's':
+                                               fprintf(stderr, "String keyword expected\n");
+                                               print_opt_string_list();
+                                               break;
+                               }
+                               return -1;
+               }
+
+       if ((opt.flags & FLAG_DUMP) && opt.string != NULL)
+       {
+               fprintf(stderr, "Options --string and --dump are mutually exclusive\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+void print_help(void)
+{
+       static const char *help =
+               "Usage: vpddecode [OPTIONS]\n"
+               "Options are:\n"
+               " -d, --dev-mem FILE     Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n"
+               " -h, --help             Display this help text and exit\n"
+               " -s, --string KEYWORD   Only display the value of the given VPD string\n"
+               " -u, --dump             Do not decode the VPD records\n"
+               " -V, --version          Display the version and exit\n";
+
+       printf("%s", help);
+}
diff --git a/vpdopt.h b/vpdopt.h
new file mode 100644 (file)
index 0000000..fceb552
--- /dev/null
+++ b/vpdopt.h
@@ -0,0 +1,45 @@
+/*
+ * Command line handling of vpddecode
+ * This file is part of the dmidecode project.
+ *
+ *   Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org>
+ *
+ *   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 <sys/types.h>
+
+struct string_keyword
+{
+       const char *keyword;
+       off_t offset;
+       size_t len;
+};
+
+struct opt
+{
+       const char *devmem;
+       unsigned int flags;
+       const struct string_keyword *string;
+};
+extern struct opt opt;
+
+#define FLAG_VERSION            (1 << 0)
+#define FLAG_HELP               (1 << 1)
+#define FLAG_DUMP               (1 << 2)
+#define FLAG_QUIET              (1 << 3)
+
+int parse_command_line(int argc, char * const argv[]);
+void print_help(void);