diff options
| -rw-r--r-- | AUTHORS | 86 | ||||
| -rw-r--r-- | CHANGELOG | 1383 | ||||
| -rw-r--r-- | LICENSE | 340 | ||||
| -rw-r--r-- | Makefile | 140 | ||||
| -rw-r--r-- | README | 116 | ||||
| -rw-r--r-- | biosdecode.c | 669 | ||||
| -rw-r--r-- | config.h | 29 | ||||
| -rw-r--r-- | dmidecode.c | 4704 | ||||
| -rw-r--r-- | dmidecode.h | 29 | ||||
| -rw-r--r-- | dmioem.c | 129 | ||||
| -rw-r--r-- | dmioem.h | 25 | ||||
| -rw-r--r-- | dmiopt.c | 316 | ||||
| -rw-r--r-- | dmiopt.h | 47 | ||||
| -rw-r--r-- | man/biosdecode.8 | 83 | ||||
| -rw-r--r-- | man/dmidecode.8 | 246 | ||||
| -rw-r--r-- | man/ownership.8 | 37 | ||||
| -rw-r--r-- | man/vpddecode.8 | 74 | ||||
| -rw-r--r-- | ownership.c | 214 | ||||
| -rw-r--r-- | types.h | 62 | ||||
| -rw-r--r-- | util.c | 219 | ||||
| -rw-r--r-- | util.h | 30 | ||||
| -rw-r--r-- | version.h | 1 | ||||
| -rw-r--r-- | vpddecode.c | 201 | ||||
| -rw-r--r-- | vpdopt.c | 157 | ||||
| -rw-r--r-- | vpdopt.h | 45 | 
25 files changed, 9382 insertions, 0 deletions
| @@ -0,0 +1,86 @@ +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 +Andrey Matveyev +Stefan Tauner +Naga Chumbalkar diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..fd489c8 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,1383 @@ +2013-04-17  Anton Arapov  <anton@redhat.com> + +	Update to support SMBIOS specification version 2.8.0. + +	* dmidecode.c: Correct processor family name (DMI type 4). +	* dmidecode.c: Correct typo in processor upgrade type (DMI type 4). +	* dmidecode.c: Add 9 new processor families (DMI type 4). +	* dmidecode.c: Add 2 new Intel socket types (DMI type 4). +	* dmidecode.c: Add Min/Max/Configured memory voltages (DMI type 17). +	* dmidecode.c: Add LRDIMM to memory device list (DMI type 17). + +2012-03-26  Anton Arapov  <anton@redhat.com> + +	* man/dmidecode.8: Add missing DMI type introduced with SMBIOS 2.7+, and +	  include the information about the extra output when dmidecode is run +	  on a hardware that has non-supported SMBIOS version. + +2012-03-12  Anton Arapov  <anton@redhat.com> + +	* dmioem.c: Add "PXE" to the HP OEM Type 209 output so it is similar to +	  the "iSCSI" description in HP OEM Type 221. Patch from Naga Chumbalkar. + +2011-11-18  Jean Delvare  <khali@linux-fr.org> + +	* dmidecode.c: Properly print the hexadecimal value of invalid +	  string characters. + +2011-11-14  Anton Arapov  <anton@redhat.com> + +	* dmidecode.c: Make dmi_chassis_type aware of the lock bit. +	  Patch from Stefan Tauner. +	* config.h: Haiku dropped the _BEOS_ definition in favor of its own +	  platform identification _HAIKU_. Patch from Francois Revol. + +2011-04-20  Jean Delvare  <khali@linux-fr.org> + +	Update to support SMBIOS specification version 2.7.1. + +	* dmidecode.c: Add 6 AMD processor families (DMI type 4). +	* dmidecode.c: Add cache associativity value +	  "20-way Set-associative" (DMI type 7). +	* dmidecode.c: Add PCI Express 3 slot types (DMI type 9). + +2011-01-25  Jean Delvare  <khali@linux-fr.org> + +	* dmidecode.c: Fix boundary checks of memory array location codes +	  (DMI type 16). Reported by Andrey Matveyev. + +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. @@ -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. + +		    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.) + +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. + +  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. + +  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 + +	    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 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 @@ -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 index 0000000..09acb43 --- /dev/null +++ b/biosdecode.c @@ -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 index 0000000..e39091f --- /dev/null +++ b/config.h @@ -0,0 +1,29 @@ +/* + * Configuration + */ + +#ifndef CONFIG_H +#define CONFIG_H + +/* Default memory device file */ +#if defined(__BEOS__) || defined(__HAIKU__) +#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 index 0000000..0599759 --- /dev/null +++ b/dmidecode.c @@ -0,0 +1,4704 @@ +/* + * 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.8.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 ? " " : "", +						       (unsigned char)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 */ +	}; + +	code &= 0x7F; /* bits 6:0 are chassis type, 7th bit is the lock bit */ + +	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" }, +		{ 0x3D, "Opteron 6200" }, +		{ 0x3E, "Opteron 4200" }, +		{ 0x3F, "FX" }, + +		{ 0x40, "MIPS" }, +		{ 0x41, "MIPS R4000" }, +		{ 0x42, "MIPS R4200" }, +		{ 0x43, "MIPS R4400" }, +		{ 0x44, "MIPS R4600" }, +		{ 0x45, "MIPS R10000" }, +		{ 0x46, "C-Series" }, +		{ 0x47, "E-Series" }, +		{ 0x48, "A-Series" }, +		{ 0x49, "G-Series" }, +		{ 0x4A, "Z-Series" }, +		{ 0x4B, "R-Series" }, +		{ 0x4C, "Opteron 4300" }, +		{ 0x4D, "Opteron 6300" }, +		{ 0x4E, "Opteron 3300" }, +		{ 0x4F, "FirePro" }, + +		{ 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" }, + +		{ 0xE4, "Opteron 3000" }, +		{ 0xE5, "Sempron II" }, +		{ 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 <= 0x3E) /* AMD */ +	      || (type >= 0x46 && type <= 0x49) /* 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", +		"Socket rPGA988B", +		"Socket BGA1023", +		"Socket BGA1224", +		"Socket BGA1155", +		"Socket LGA1356", +		"Socket LGA2011", +		"Socket FS1", +		"Socket FS2", +		"Socket FM1", +		"Socket FM2", +		"Socket LGA2011-3", +		"Socket LGA1356-3" /* 0x2C */ +	}; + +	if (code >= 0x01 && code <= 0x2A) +		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", +		"20-way Set-associative" /* 0x0E */ +	}; + +	if (code >= 0x01 && code <= 0x0E) +		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", +		"PCI Express 3", +		"PCI Express 3 x1", +		"PCI Express 3 x2", +		"PCI Express 3 x4", +		"PCI Express 3 x8", +		"PCI Express 3 x16" /* 0xB6 */ +	}; + +	if (code >= 0x01 && code <= 0x13) +		return type[code - 0x01]; +	if (code >= 0xA0 && code <= 0xB6) +		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 <= 0xA3) +		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 void dmi_memory_voltage_value(u16 code) +{ +	if (code == 0) +		printf(" Unknown"); +	else +		printf(" %.3f V", (float)(i16)code / 1000); +} + +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)", +		"LRDIMM"  /* 15 */ +	}; + +	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])); +			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"); +			if (h->length < 0x28) break; +			printf("\tMinimum voltage: "); +			dmi_memory_voltage_value(WORD(data + 0x22)); +			printf("\n"); +			printf("\tMaximum voltage: "); +			dmi_memory_voltage_value(WORD(data + 0x24)); +			printf("\n"); +			printf("\tConfigured voltage: "); +			dmi_memory_voltage_value(WORD(data + 0x26)); +			printf("\n"); +			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 index 0000000..cae627b --- /dev/null +++ b/dmidecode.h @@ -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 index 0000000..a2b5a68 --- /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 PXE 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 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 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 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 index 0000000..46bea95 --- /dev/null +++ b/man/biosdecode.8 @@ -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 index 0000000..9ca2d82 --- /dev/null +++ b/man/dmidecode.8 @@ -0,0 +1,246 @@ +.TH DMIDECODE 8 "March 2012" "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. +.P +Please note in case of +.B dmidecode +is run on a system with BIOS that boasts new SMBIOS specification, which +is not supported by the tool yet, it will print out relevant message in +addition to requested data on the very top of the output. Thus informs the +output data is not reliable. + +.SH "DMI TYPES" +The \s-1SMBIOS\s0 specification defines the following \s-1DMI\s0 types: + +.TS +r l +__ +r l. +Type	Information +0	BIOS +1	System +2	Baseboard +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 Devices Extended Information +42	Management Controller Host Interface +.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 index 0000000..f24ef94 --- /dev/null +++ b/man/ownership.8 @@ -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 index 0000000..c9e4acf --- /dev/null +++ b/man/vpddecode.8 @@ -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 index 0000000..d79af12 --- /dev/null +++ b/ownership.c @@ -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; +} @@ -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 @@ -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; +} @@ -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 index 0000000..140d334 --- /dev/null +++ b/version.h @@ -0,0 +1 @@ +#define VERSION "2.12" diff --git a/vpddecode.c b/vpddecode.c new file mode 100644 index 0000000..2b0d27c --- /dev/null +++ b/vpddecode.c @@ -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 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 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); | 
