diff options
-rw-r--r-- | AUTHORS | 59 | ||||
-rw-r--r-- | CHANGELOG | 993 | ||||
-rw-r--r-- | LICENSE | 340 | ||||
-rw-r--r-- | Makefile | 148 | ||||
-rw-r--r-- | README | 146 | ||||
-rw-r--r-- | biosdecode.c | 666 | ||||
-rw-r--r-- | catsprintf.c | 20 | ||||
-rw-r--r-- | catsprintf.h | 10 | ||||
-rw-r--r-- | config.h | 25 | ||||
-rw-r--r-- | dmidecode.c | 4140 | ||||
-rw-r--r-- | dmidecode.h | 40 | ||||
-rw-r--r-- | dmidecodemodule.c | 170 | ||||
-rw-r--r-- | dmioem.c | 128 | ||||
-rw-r--r-- | dmioem.h | 25 | ||||
-rw-r--r-- | dmiopt.c | 308 | ||||
-rw-r--r-- | dmiopt.h | 46 | ||||
-rw-r--r-- | global.h | 7 | ||||
-rw-r--r-- | ownership.c | 212 | ||||
-rw-r--r-- | setup.py | 5 | ||||
-rw-r--r-- | test.c | 127 | ||||
-rw-r--r-- | types.h | 62 | ||||
-rw-r--r-- | util.c | 165 | ||||
-rw-r--r-- | util.h | 8 | ||||
-rw-r--r-- | version.h | 1 | ||||
-rw-r--r-- | vpddecode.c | 202 | ||||
-rw-r--r-- | vpdopt.c | 159 | ||||
-rw-r--r-- | vpdopt.h | 45 |
27 files changed, 8257 insertions, 0 deletions
@@ -0,0 +1,59 @@ +DEVELOPER AND MAINTAINER +Jean Delvare <khali@linux-fr.org> + +ORIGINAL AUTHOR +Alan Cox <alan@redhat.com> + +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> + +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 diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..eb420c6 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,993 @@ +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 + accomodate 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 + accomodate 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 overriden 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 signedness 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 mem loop code a bit. + +2004-11-12 Jean Delvare <khali@linux-fr.org> + + * dmidecode.c: Hide bank connection type for uninstalled 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: Refactor WORD-like + macros into 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 hexa. 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__ ((usused)) 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 hexa, 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..29d4238 --- /dev/null +++ b/Makefile @@ -0,0 +1,148 @@ +# +# DMI Decode +# BIOS Decode +# +# (C) 2000-2002 Alan Cox <alan@redhat.com> +# (C) 2002-2007 Jean Delvare <khali@linux-fr.org> +# +# Licensed under the GNU Public License. +# + +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 + +PROGRAMS := go +PROGRAMS += $(shell test `uname -m 2>/dev/null` != ia64 && echo biosdecode ownership vpddecode) +# BSD make doesn't understand the $(shell) syntax above, it wants the != +# syntax below. GNU make ignores the line below so in the end both BSD +# make and GNU make are happy. +PROGRAMS != echo dmidecode ; test `uname -m 2>/dev/null` != ia64 && echo biosdecode ownership vpddecode + + + +all : $(PROGRAMS) + python setup.py clean + python setup.py build + sudo python setup.py install + ldd /usr/lib/python2.4/site-packages/dmidecode.so + python -c 'import dmidecode' + +#. NiMA... +go: test.c catsprintf.o libdmidecode.so dmidecode.o dmiopt.o dmioem.o util.o + gcc -o go test.c -L. -I/usr/include/python2.4 -ldmidecode catsprintf.o dmidecode.o dmiopt.o dmioem.o util.o +libdmidecode.so: dmidecode.o + gcc -shared $< -o $@ +catsprintf.o: catsprintf.c catsprintf.h + $(CC) $(CFLAGS) -c $< -o $@ +#. ...NiMA + +# +# 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 + +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 : + python setup.py clean + $(RM) *.so *.o $(PROGRAMS) core + rm -rf build @@ -0,0 +1,146 @@ +** 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). + +Part of the dmidecode code can be found in the Linux kernel, where DMI data +is used to enable or disable specific portions of 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 and Cygwin 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. 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 ** + +MODEL SPECIFIC ISSUES + +Dmidecode used not to work on IBM T-series laptops nor on Fujitsu-Siemens +S-series laptops under Linux. This was due to the fact that the DMI table +is at a memory location we couldn't seem to reach through /dev/mem. Although +I believe this reveals a problem in the Linux kernel, which should be fixed, +a workaround was found by Chad Smith, and we are using it for now. See the +IA-64 subsection below for more details. I posted about this problem on the +LKML but never received any answer. Since then, the list of affected systems +was extended to IBM X-series laptops and xSeries x445 servers. + +IA-64 + +Dmidecode used to have problems on IA-64 systems. The first reason for +this is that dmidecode accesses the DMI table through /dev/mem, and reading +this file on an IA-64 system sometimes leads to a crash. A second reason is +that the method for locating the above-mentioned table differs on IA-64 +(compared to x86), so dmidecode was likely to miss the table entry point. +This complex issue was reported by Glen Foster and Chad Smith from HP. We +have since been working on a solution, and dmidecode now supports IA-64 +systems. Chad Smith noticed that, for some obscure reason, accessing the +/dev/mem file using mmap() instead of read() would work. Then, he wrote a +patch to export the DMI table address from the internal EFI table to /proc, +so dmidecode doesn't have to scan /dev/mem for it anymore. This patch was +since integrated into the main ia64 patch. Finally, I added the required +code to make it all work. So, in order to have dmidecode work on your IA-64 +system, you need two things: + - dmidecode version 2.2 or later; + - an ia64 patched 2.4 kernel, using linux-2.4.21-ia64-030702.diff or any + later version, or a 2.6 kernel. +Chad Smith tested dmidecode successfully on two different IA-64 systems, and +success has been reported by other users too. Non-Linux systems are not +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. See the IA-64 subsection above for details. + +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..354234e --- /dev/null +++ b/biosdecode.c @@ -0,0 +1,666 @@ +/* + * BIOS Decode + * + * (C) 2000-2002 Alan Cox <alan@redhat.com> + * (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. + * + * 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) +{ + (void) len; + int i; + + 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 and strncmp */ +static inline 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/catsprintf.c b/catsprintf.c new file mode 100644 index 0000000..e0914c4 --- /dev/null +++ b/catsprintf.c @@ -0,0 +1,20 @@ +#include "catsprintf.h" + +int catsprintf(char *buf, const char *format, ...) { + static int i = 0; + + va_list arg; /*will point to each unnamed argument in turn*/ + va_start(arg, format); /* point to first element after fmt*/ + + + char b[8192]; + int c = vsprintf (b, format, arg); + i += strlen(b); + //printf("%d %s (%d)\n", i, b, strlen(b)); + + strcat(buf, b); + + va_end(arg); /*cleanup*/ + + return c; +} diff --git a/catsprintf.h b/catsprintf.h new file mode 100644 index 0000000..992cb2e --- /dev/null +++ b/catsprintf.h @@ -0,0 +1,10 @@ +#ifndef CAT +#define CAT 1 + +#include <stdarg.h> +#include <string.h> +#include <stdio.h> +int catsprintf(char *buf, const char *format, ...); +/* sed -i -e 's/\<printf(/catsprintf(buffer, /g' dmidecode.c */ + +#endif diff --git a/config.h b/config.h new file mode 100644 index 0000000..c1d7d03 --- /dev/null +++ b/config.h @@ -0,0 +1,25 @@ +/* + * Configuration + */ + +#ifndef CONFIG_H +#define CONFIG_H + +/* Default memory device file */ +#ifdef __BEOS__ +#define DEFAULT_MEM_DEV "/dev/misc/mem" +#else +#define DEFAULT_MEM_DEV "/dev/mem" +#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..966b0d5 --- /dev/null +++ b/dmidecode.c @@ -0,0 +1,4140 @@ +/* + * DMI Decode + * + * (C) 2000-2002 Alan Cox <alan@redhat.com> + * (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. + * + * 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.5" 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 31 + * "Intel Processor Identification and the CPUID Instruction" + * http://developer.intel.com/design/xeon/applnots/241618.htm + * - DMTF Master MIF version 040707 + * "DMTF approved standard groups" + * http://www.dmtf.org/standards/dmi + * - 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.18 + * "CPUID Specification" + * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf + */ + +#include <stdio.h> +#include <string.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" + +#include "global.h" +#include "catsprintf.h" + +static const char *out_of_spec = "<OUT OF SPEC>"; +static const char *bad_index = "<BAD INDEX>"; + +/* + * Type-independant Stuff + */ + +const char *dmi_string(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; + + /* 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" /* 39 */ + }; + + if(code<=39) + 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; +} + +void dmi_dump(struct dmi_header *h, const char *prefix) +{ + int row, i; + const char *s; + + catsprintf(buffer, "%sHeader and Data:\n", prefix); + for(row=0; row<((h->length-1)>>4)+1; row++) + { + catsprintf(buffer, "%s\t", prefix); + for(i=0; i<16 && i<h->length-(row<<4); i++) + catsprintf(buffer, "%s%02X", i?" ":"", (h->data)[(row<<4)+i]); + catsprintf(buffer, "\n"); + } + + if((h->data)[h->length] || (h->data)[h->length+1]) + { + catsprintf(buffer, "%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++) + { + catsprintf(buffer, "%s\t", prefix); + for(j=0; j<16 && j<l-(row<<4); j++) + catsprintf(buffer, "%s%02X", j?" ":"", + s[(row<<4)+j]); + catsprintf(buffer, "\n"); + } + catsprintf(buffer, "%s\t\"%s\"\n", prefix, s); + } + else + catsprintf(buffer, "%s\t%s\n", prefix, s); + } + } +} + +/* + * 3.3.1 BIOS Information (Type 0) + */ + +static void dmi_bios_runtime_size(u32 code) +{ + if(code&0x000003FF) + catsprintf(buffer, " %u bytes", code); + else + catsprintf(buffer, " %u kB", code>>10); +} + +static void dmi_bios_characteristics(u64 code, const char *prefix) +{ + /* 3.3.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)) + { + catsprintf(buffer, "%s%s\n", + prefix, characteristics[0]); + return; + } + + for(i=4; i<=31; i++) + if(code.l&(1<<i)) + catsprintf(buffer, "%s%s\n", + prefix, characteristics[i-3]); +} + +static void dmi_bios_characteristics_x1(u8 code, const char *prefix) +{ + /* 3.3.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)) + catsprintf(buffer, "%s%s\n", + prefix, characteristics[i]); +} + +static void dmi_bios_characteristics_x2(u8 code, const char *prefix) +{ + /* 3.3.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" /* 2 */ + }; + int i; + + for(i=0; i<=2; i++) + if(code&(1<<i)) + catsprintf(buffer, "%s%s\n", + prefix, characteristics[i]); +} + +/* + * 3.3.2 System Information (Type 1) + */ + +void dmi_system_uuid(u8 *p) +{ + 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) + { + catsprintf(buffer, "Not Present"); + return; + } + if(only0x00) + { + catsprintf(buffer, "Not Settable"); + return; + } + + catsprintf(buffer, "%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) +{ + /* 3.3.2.1 */ + 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; +} + +/* + * 3.3.3 Base Board Information (Type 2) + */ + +static void dmi_base_board_features(u8 code, const char *prefix) +{ + /* 3.3.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) + catsprintf(buffer, " None\n"); + else + { + int i; + + catsprintf(buffer, "\n"); + for(i=0; i<=4; i++) + if(code&(1<<i)) + catsprintf(buffer, "%s%s\n", + prefix, features[i]); + } +} + +static const char *dmi_base_board_type(u8 code) +{ + /* 3.3.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, u8 *p, const char *prefix) +{ + int i; + + catsprintf(buffer, "%sContained Object Handles: %u\n", + prefix, count); + for(i=0; i<count; i++) + catsprintf(buffer, "%s\t0x%04X\n", + prefix, WORD(p+sizeof(u16)*i)); +} + +/* + * 3.3.4 Chassis Information (Type 3) + */ + +const char *dmi_chassis_type(u8 code) +{ + /* 3.3.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", /* master.mif says System */ + "Expansion Chassis", + "Sub Chassis", + "Bus Expansion Chassis", + "Peripheral Chassis", + "RAID Chassis", + "Rack Mount Chassis", + "Sealed-case PC", + "Multi-system", + "CompactPCI", + "AdvancedTCA" /* 0x1B */ + }; + + if(code>=0x01 && code<=0x1B) + 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) +{ + /* 3.3.4.2 */ + static const char *state[]={ + "Other", /* 0x01 */ + "Unknown", + "Safe", /* master.mif says OK */ + "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) +{ + /* 3.3.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) + catsprintf(buffer, " Unspecified"); + else + catsprintf(buffer, " %u U", code); +} + +static void dmi_chassis_power_cords(u8 code) +{ + if(code==0x00) + catsprintf(buffer, " Unspecified"); + else + catsprintf(buffer, " %u", code); +} + +static void dmi_chassis_elements(u8 count, u8 len, u8 *p, const char *prefix) +{ + int i; + + catsprintf(buffer, "%sContained Elements: %u\n", + prefix, count); + for(i=0; i<count; i++) + { + if(len>=0x03) + { + catsprintf(buffer, "%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]) + catsprintf(buffer, "%u", p[1+i*len]); + else + catsprintf(buffer, "%u-%u", p[1+i*len], p[2+i*len]); + catsprintf(buffer, ")\n"); + } + } +} + +/* + * 3.3.5 Processor Information (Type 4) + */ + +static const char *dmi_processor_type(u8 code) +{ + /* 3.3.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; +} + +const char *dmi_processor_family(u8 code) +{ + /* 3.3.5.2 */ + static const char *family[256]={ + NULL, /* 0x00 */ + "Other", + "Unknown", + "8086", + "80286", + "80386", + "80486", + "8087", + "80287", + "80387", + "80487", + "Pentium", + "Pentium Pro", + "Pentium II", + "Pentium MMX", + "Celeron", + "Pentium II Xeon", + "Pentium III", + "M1", + "M2", + NULL, /* 0x14 */ + NULL, + NULL, + NULL, /* 0x17 */ + "Duron", + "K5", + "K6", + "K6-2", + "K6-3", + "Athlon", + "AMD2900", + "K6-2+", + "Power PC", + "Power PC 601", + "Power PC 603", + "Power PC 603+", + "Power PC 604", + "Power PC 620", + "Power PC x704", + "Power PC 750", + NULL, /* 0x28 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL,/* 0x2F */ + "Alpha", + "Alpha 21064", + "Alpha 21066", + "Alpha 21164", + "Alpha 21164PC", + "Alpha 21164a", + "Alpha 21264", + "Alpha 21364", + NULL, /* 0x38 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* 0x3F */ + "MIPS", + "MIPS R4000", + "MIPS R4200", + "MIPS R4400", + "MIPS R4600", + "MIPS R10000", + NULL, /* 0x46 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* 0x4F */ + "SPARC", + "SuperSPARC", + "MicroSPARC II", + "MicroSPARC IIep", + "UltraSPARC", + "UltraSPARC II", + "UltraSPARC IIi", + "UltraSPARC III", + "UltraSPARC IIIi", + NULL, /* 0x59 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* 0x5F */ + "68040", + "68xxx", + "68000", + "68010", + "68020", + "68030", + NULL, /* 0x66 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* 0x6F */ + "Hobbit", + NULL, /* 0x71 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* 0x77 */ + "Crusoe TM5000", + "Crusoe TM3000", + "Efficeon TM8000", + NULL, /* 0x7B */ + NULL, + NULL, + NULL, + NULL, /* 0x7F */ + "Weitek", + NULL, /* 0x81 */ + "Itanium", + "Athlon 64", + "Opteron", + "Sempron", + "Turion 64", + "Dual-Core Opteron", + "Athlon 64 X2", + NULL, /* 0x89 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* 0x8F */ + "PA-RISC", + "PA-RISC 8500", + "PA-RISC 8000", + "PA-RISC 7300LC", + "PA-RISC 7200", + "PA-RISC 7100LC", + "PA-RISC 7100", + NULL, /* 0x97 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* 0x9F */ + "V30", + NULL, /* 0xA1 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* 0xAF */ + "Pentium III Xeon", + "Pentium III Speedstep", + "Pentium 4", + "Xeon", + "AS400", + "Xeon MP", + "Athlon XP", + "Athlon MP", + "Itanium 2", + "Pentium M", + "Celeron D", + "Pentium D", + "Pentium EE", + NULL, /* 0xBD */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* 0xC7 */ + "IBM390", + "G4", + "G5", + NULL, /* 0xCB */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* 0xF9 */ + "i860", + "i960", + NULL, /* 0xFC */ + NULL, + NULL, + NULL /* 0xFF */ + /* master.mif has values beyond that, but they can't be used for DMI */ + }; + + if(family[code]!=NULL) + return family[code]; + return out_of_spec; +} + +static void dmi_processor_id(u8 type, u8 *p, const char *version, const char *prefix) +{ + /* Intel AP-485 revision 31, table 3-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 (Fast floating-point save and restore)", + "SSE (Streaming SIMD extensions)", + "SSE2 (Streaming SIMD extensions 2)", + "SS (Self-snoop)", + "HTT (Hyper-threading technology)", + "TM (Thermal monitor supported)", + "IA64 (IA64 capabilities)", + "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. + */ + catsprintf(buffer, "%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. + */ + catsprintf(buffer, "%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 + { + catsprintf(buffer, "%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<=0x13) /* Intel, Cyrix */ + || (type>=0xB0 && type<=0xB3) /* Intel */ + || type==0xB5 /* Intel */ + || (type>=0xB9 && type<=0xBC)) /* Intel */ + sig=1; + else if((type>=0x18 && type<=0x1D) /* AMD */ + || type==0x1F /* AMD */ + || (type>=0xB6 && type<=0xB7) /* AMD */ + || (type>=0x83 && type<=0x88)) /* 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) + sig=1; + else if(strncmp(version, "AMD Athlon(TM)", 14)==0 + || strncmp(version, "AMD Opteron(tm)", 15)==0) + sig=2; + else + return; + } + else /* not X86-class */ + return; + + eax=DWORD(p); + edx=DWORD(p+4); + switch(sig) + { + case 1: /* Intel */ + catsprintf(buffer, "%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 */ + catsprintf(buffer, "%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); + catsprintf(buffer, "%sFlags:", prefix); + if((edx&0xFFEFFBFF)==0) + catsprintf(buffer, " None\n"); + else + { + int i; + + catsprintf(buffer, "\n"); + for(i=0; i<=31; i++) + if(flags[i]!=NULL && edx&(1<<i)) + catsprintf(buffer, "%s\t%s\n", prefix, flags[i]); + } +} + +static void dmi_processor_voltage(u8 code) +{ + /* 3.3.5.4 */ + static const char *voltage[]={ + "5.0 V", /* 0 */ + "3.3 V", + "2.9 V" /* 2 */ + }; + int i; + + if(code&0x80) + catsprintf(buffer, " %.1f V", (float)(code&0x7f)/10); + else + { + for(i=0; i<=2; i++) + if(code&(1<<i)) + catsprintf(buffer, " %s", voltage[i]); + if(code==0x00) + catsprintf(buffer, " Unknown"); + } +} + +void dmi_processor_frequency(u8 *p) +{ + u16 code = WORD(p); + + if(code) + catsprintf(buffer, "%u MHz", code); + else + catsprintf(buffer, "Unknown"); +} + +static const char *dmi_processor_status(u8 code) +{ + static const char *status[]={ + "Unknown", /* 0x00 */ + "Enabled", + "Disabled By User", + "Disabled By BIOS", + "Idle", /* 0x04 */ + "Other" /* 0x07 */ + }; + + if(code<=0x04) + return status[code]; + if(code==0x07) + return status[0x05]; + return out_of_spec; +} + +static const char *dmi_processor_upgrade(u8 code) +{ + /* 3.3.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" /* 0x15 */ + }; + + if(code>=0x01 && code<=0x15) + 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) + catsprintf(buffer, " Not Provided"); + else + catsprintf(buffer, " No %s Cache", level); + } + else + catsprintf(buffer, " 0x%04X", code); +} + +static void dmi_processor_characteristics(u16 code, const char *prefix) +{ + /* 3.3.5.9 */ + static const char *characteristics[]={ + "64-bit capable" /* 2 */ + }; + + if((code&0x0004)==0) + catsprintf(buffer, " None\n"); + else + { + int i; + + catsprintf(buffer, "\n"); + for(i=2; i<=2; i++) + if(code&(1<<i)) + catsprintf(buffer, "%s%s\n", prefix, characteristics[i-2]); + } +} + +/* + * 3.3.6 Memory Controller Information (Type 5) + */ + +static const char *dmi_memory_controller_ed_method(u8 code) +{ + /* 3.3.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) +{ + /* 3.3.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) + catsprintf(buffer, " None\n"); + else + { + int i; + + catsprintf(buffer, "\n"); + for(i=0; i<=5; i++) + if(code&(1<<i)) + catsprintf(buffer, "%s%s\n", prefix, capabilities[i]); + } +} + +static const char* dmi_memory_controller_interleave(u8 code) +{ + /* 3.3.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) +{ + /* 3.3.6.4 */ + const char *speeds[]={ + "Other", /* 0 */ + "Unknown", + "70 ns", + "60 ns", + "50 ns" /* 4 */ + }; + + if((code&0x001F)==0) + catsprintf(buffer, " None\n"); + else + { + int i; + + catsprintf(buffer, "\n"); + for(i=0; i<=4; i++) + if(code&(1<<i)) + catsprintf(buffer, "%s%s\n", prefix, speeds[i]); + } +} + +static void dmi_memory_controller_slots(u8 count, u8 *p, const char *prefix) +{ + int i; + + catsprintf(buffer, "%sAssociated Memory Slots: %u\n", + prefix, count); + for(i=0; i<count; i++) + catsprintf(buffer, "%s\t0x%04X\n", + prefix, WORD(p+sizeof(u16)*i)); +} + +/* + * 3.3.7 Memory Module Information (Type 6) + */ + +static void dmi_memory_module_types(u16 code, const char *sep) +{ + /* 3.3.7.1 */ + static const char *types[]={ + "Other", /* 0 */ + "Unknown", + "Standard", + "FPM", + "EDO", + "Parity", + "ECC", + "SIMM", + "DIMM", + "Burst EDO", + "SDRAM" /* 10 */ + }; + + if((code&0x07FF)==0) + catsprintf(buffer, " None"); + else + { + int i; + + for(i=0; i<=10; i++) + if(code&(1<<i)) + catsprintf(buffer, "%s%s", sep, types[i]); + } +} + +static void dmi_memory_module_connections(u8 code) +{ + if(code==0xFF) + catsprintf(buffer, " None"); + else + { + if((code&0xF0)!=0xF0) + catsprintf(buffer, " %u", code>>4); + if((code&0x0F)!=0x0F) + catsprintf(buffer, " %u", code&0x0F); + } +} + +static void dmi_memory_module_speed(u8 code) +{ + if(code==0) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u ns", code); +} + +static void dmi_memory_module_size(u8 code) +{ + /* 3.3.7.2 */ + switch(code&0x7F) + { + case 0x7D: + catsprintf(buffer, " Not Determinable"); + break; + case 0x7E: + catsprintf(buffer, " Disabled"); + break; + case 0x7F: + catsprintf(buffer, " Not Installed"); + return; + default: + catsprintf(buffer, " %u MB", 1<<(code&0x7F)); + } + + if(code&0x80) + catsprintf(buffer, " (Double-bank Connection)"); + else + catsprintf(buffer, " (Single-bank Connection)"); +} + +static void dmi_memory_module_error(u8 code, const char *prefix) +{ + if(code&(1<<2)) + catsprintf(buffer, " See Event Log\n"); + else + { if((code&0x03)==0) + catsprintf(buffer, " OK\n"); + if(code&(1<<0)) + catsprintf(buffer, "%sUncorrectable Errors\n", prefix); + if(code&(1<<1)) + catsprintf(buffer, "%sCorrectable Errors\n", prefix); + } +} + +/* + * 3.3.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]; +} + +static const char *dmi_cache_location(u8 code) +{ + static const char *location[4]={ + "Internal", /* 0x00 */ + "External", + NULL, /* 0x02 */ + "Unknown" /* 0x03 */ + }; + + if(location[code]!=NULL) + return location[code]; + return out_of_spec; +} + +static void dmi_cache_size(u16 code) +{ + if(code&0x8000) + catsprintf(buffer, " %u KB", (code&0x7FFF)<<6); + else + catsprintf(buffer, " %u KB", code); +} + +static void dmi_cache_types(u16 code, const char *sep) +{ + /* 3.3.8.2 */ + static const char *types[]={ + "Other", /* 0 */ + "Unknown", + "Non-burst", + "Burst", + "Pipeline Burst", + "Synchronous", + "Asynchronous" /* 6 */ + }; + + if((code&0x007F)==0) + catsprintf(buffer, " None"); + else + { + int i; + + for(i=0; i<=6; i++) + if(code&(1<<i)) + catsprintf(buffer, "%s%s", sep, types[i]); + } +} + +static const char *dmi_cache_ec_type(u8 code) +{ + /* 3.3.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) +{ + /* 3.3.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) +{ + /* 3.3.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" /* 0x08 */ + }; + + if(code>=0x01 && code<=0x08) + return type[code-0x01]; + return out_of_spec; +} + +/* + * 3.3.9 Port Connector Information (Type 8) + */ + +static const char *dmi_port_connector_type(u8 code) +{ + /* 3.3.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) +{ + /* 3.3.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; +} + +/* + * 3.3.10 System Slots (Type 9) + */ + +static const char *dmi_slot_type(u8 code) +{ + /* 3.3.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" /* 0xA5 */ + }; + + if(code>=0x01 && code<=0x13) + return type[code-0x01]; + if(code>=0xA0 && code<=0xA5) + return type_0xA0[code-0xA0]; + return out_of_spec; +} + +static const char *dmi_slot_bus_width(u8 code) +{ + /* 3.3.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) +{ + /* 3.3.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) +{ + /* 3.3.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) +{ + /* 3.3.10.5 */ + switch(type) + { + case 0x04: /* MCA */ + catsprintf(buffer, "%sID: %u\n", prefix, code1); + break; + case 0x05: /* EISA */ + catsprintf(buffer, "%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 */ + catsprintf(buffer, "%sID: %u\n", prefix, code1); + break; + case 0x07: /* PCMCIA */ + catsprintf(buffer, "%sID: Adapter %u, Socket %u\n", prefix, code1, code2); + break; + } +} + +static void dmi_slot_characteristics(u8 code1, u8 code2, const char *prefix) +{ + /* 3.3.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 */ + }; + /* 3.3.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)) + catsprintf(buffer, " Unknown\n"); + else if((code1&0xFE)==0 && (code2&0x07)==0) + catsprintf(buffer, " None\n"); + else + { + int i; + + catsprintf(buffer, "\n"); + for(i=1; i<=7; i++) + if(code1&(1<<i)) + catsprintf(buffer, "%s%s\n", prefix, characteristics1[i-1]); + for(i=0; i<=2; i++) + if(code2&(1<<i)) + catsprintf(buffer, "%s%s\n", prefix, characteristics2[i]); + } +} + +/* + * 3.3.11 On Board Devices Information (Type 10) + */ + +static const char *dmi_on_board_devices_type(u8 code) +{ + /* 3.3.11.1 */ + 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(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) + catsprintf(buffer, "%sOn Board Device Information\n", + prefix); + else + catsprintf(buffer, "%sOn Board Device %d Information\n", + prefix, i+1); + catsprintf(buffer, "%s\tType: %s\n", + prefix, dmi_on_board_devices_type(p[2*i]&0x7F)); + catsprintf(buffer, "%s\tStatus: %s\n", + prefix, p[2*i]&0x80?"Enabled":"Disabled"); + catsprintf(buffer, "%s\tDescription: %s\n", + prefix, dmi_string(h, p[2*i+1])); + } +} + +/* + * 3.3.12 OEM Strings (Type 11) + */ + +static void dmi_oem_strings(struct dmi_header *h, const char *prefix) +{ + u8 *p=h->data+4; + u8 count=p[0x00]; + int i; + + for(i=1; i<=count; i++) + catsprintf(buffer, "%sString %d: %s\n", + prefix, i, dmi_string(h, i)); +} + +/* + * 3.3.13 System Configuration Options (Type 12) + */ + +static void dmi_system_configuration_options(struct dmi_header *h, const char *prefix) +{ + u8 *p=h->data+4; + u8 count=p[0x00]; + int i; + + for(i=1; i<=count; i++) + catsprintf(buffer, "%sOption %d: %s\n", + prefix, i, dmi_string(h, i)); +} + +/* + * 3.3.14 BIOS Language Information (Type 13) + */ + +static void dmi_bios_languages(struct dmi_header *h, const char *prefix) +{ + u8 *p=h->data+4; + u8 count=p[0x00]; + int i; + + for(i=1; i<=count; i++) + catsprintf(buffer, "%s%s\n", + prefix, dmi_string(h, i)); +} + +/* + * 3.3.15 Group Associations (Type 14) + */ + +static void dmi_group_associations_items(u8 count, u8 *p, const char *prefix) +{ + int i; + + for(i=0; i<count; i++) + { + catsprintf(buffer, "%s0x%04X (%s)\n", + prefix, WORD(p+3*i+1), + dmi_smbios_structure_type(p[3*i])); + } +} + +/* + * 3.3.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 */ + }; + + catsprintf(buffer, " %s, %s", + valid[(code>>0)&1], full[(code>>1)&1]); +} + +static void dmi_event_log_address(u8 method, u8 *p) +{ + /* 3.3.16.3 */ + switch(method) + { + case 0x00: + case 0x01: + case 0x02: + catsprintf(buffer, " Index 0x%04X, Data 0x%04X", WORD(p), WORD(p+2)); + break; + case 0x03: + catsprintf(buffer, " 0x%08X", DWORD(p)); + break; + case 0x04: + catsprintf(buffer, " 0x%04X", WORD(p)); + break; + default: + catsprintf(buffer, " 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) +{ + /* 3.3.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) +{ + /* 3.3.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, u8 *p, const char *prefix) +{ + /* 3.3.16.1 */ + int i; + + for(i=0; i<count; i++) + { + if(len>=0x02) + { + catsprintf(buffer, "%sDescriptor %u: %s\n", + prefix, i+1, dmi_event_log_descriptor_type(p[i*len])); + catsprintf(buffer, "%sData Format %u: %s\n", + prefix, i+1, dmi_event_log_descriptor_format(p[i*len+1])); + } + } +} + +/* + * 3.3.17 Physical Memory Array (Type 16) + */ + +static const char *dmi_memory_array_location(u8 code) +{ + /* 3.3.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, master.mif says 16 */ + }; + 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", + "PC-98/Card Slot Add-on Card" /* 0xA4, from master.mif */ + }; + + if(code>=0x01 && code<=0x0A) + return location[code-0x01]; + if(code>=0xA0 && code<=0xA4) + return location_0xA0[code-0xA0]; + return out_of_spec; +} + +static const char *dmi_memory_array_use(u8 code) +{ + /* 3.3.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) +{ + /* 3.3.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_capacity(u32 code) +{ + if(code==0x8000000) + catsprintf(buffer, " Unknown"); + else + { + if((code&0x000FFFFF)==0) + catsprintf(buffer, " %u GB", code>>20); + else if((code&0x000003FF)==0) + catsprintf(buffer, " %u MB", code>>10); + else + catsprintf(buffer, " %u kB", code); + } +} + +static void dmi_memory_array_error_handle(u16 code) +{ + if(code==0xFFFE) + catsprintf(buffer, " Not Provided"); + else if(code==0xFFFF) + catsprintf(buffer, " No Error"); + else + catsprintf(buffer, " 0x%04X", code); +} + +/* + * 3.3.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) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u bits", code); +} + +static void dmi_memory_device_size(u16 code) +{ + if(code==0) + catsprintf(buffer, " No Module Installed"); + else if(code==0xFFFF) + catsprintf(buffer, " Unknown"); + else + { + if(code&0x8000) + catsprintf(buffer, " %u kB", code&0x7FFF); + else + catsprintf(buffer, " %u MB", code); + } +} + +static const char *dmi_memory_device_form_factor(u8 code) +{ + /* 3.3.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) + catsprintf(buffer, " None"); + else if(code==0xFF) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u", code); +} + +static const char *dmi_memory_device_type(u8 code) +{ + /* 3.3.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" /* 0x14 */ + }; + + if(code>=0x01 && code<=0x14) + return type[code-0x01]; + return out_of_spec; +} + +static void dmi_memory_device_type_detail(u16 code) +{ + /* 3.3.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" /* 12 */ + }; + + if((code&0x1FFE)==0) + catsprintf(buffer, " None"); + else + { + int i; + + for(i=1; i<=12; i++) + if(code&(1<<i)) + catsprintf(buffer, " %s", detail[i-1]); + } +} + +static void dmi_memory_device_speed(u16 code) +{ + if(code==0) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u MHz (%.1f ns)", code, (float)1000/code); +} + +/* + * 3.3.19 32-bit Memory Error Information (Type 18) + */ + +static const char *dmi_memory_error_type(u8 code) +{ + /* 3.3.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) +{ + /* 3.3.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) +{ + /* 3.3.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) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " 0x%08X", code); +} + +static void dmi_32bit_memory_error_address(u32 code) +{ + if(code==0x80000000) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " 0x%08X", code); +} + +/* + * 3.3.20 Memory Array Mapped Address (Type 19) + */ + +static void dmi_mapped_address_size(u32 code) +{ + if(code==0) + catsprintf(buffer, " Invalid"); + else if((code&0x000FFFFF)==0) + catsprintf(buffer, " %u GB", code>>20); + else if((code&0x000003FF)==0) + catsprintf(buffer, " %u MB", code>>10); + else + catsprintf(buffer, " %u kB", code); +} + +/* + * 3.3.21 Memory Device Mapped Address (Type 20) + */ + +static void dmi_mapped_address_row_position(u8 code) +{ + if(code==0) + catsprintf(buffer, " %s", out_of_spec); + else if(code==0xFF) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u", code); +} + +static void dmi_mapped_address_interleave_position(u8 code, const char *prefix) +{ + if(code!=0) + { + catsprintf(buffer, "%sInterleave Position:", prefix); + if(code==0xFF) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u", code); + catsprintf(buffer, "\n"); + } +} + +static void dmi_mapped_address_interleaved_data_depth(u8 code, const char *prefix) +{ + if(code!=0) + { + catsprintf(buffer, "%sInterleaved Data Depth:", prefix); + if(code==0xFF) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u", code); + catsprintf(buffer, "\n"); + } +} + +/* + * 3.3.22 Built-in Pointing Device (Type 21) + */ + +static const char *dmi_pointing_device_type(u8 code) +{ + /* 3.3.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) +{ + /* 3.3.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; +} + +/* + * 3.3.23 Portable Battery (Type 22) + */ + +static const char *dmi_battery_chemistry(u8 code) +{ + /* 3.3.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) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u mWh", code*multiplier); +} + +static void dmi_battery_voltage(u16 code) +{ + if(code==0) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u mV", code); +} + +static void dmi_battery_maximum_error(u8 code) +{ + if(code==0xFF) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u%%", code); +} + +/* + * 3.3.24 System Reset (Type 23) + */ + +static const char *dmi_system_reset_boot_option(u8 code) +{ + static const char *option[]={ + "Operating System", /* 0x1 */ + "System Utilities", + "Do Not Reboot" /* 0x3 */ + }; + + if(code>=0x1) + return option[code-0x1]; + return out_of_spec; +} + +static void dmi_system_reset_count(u16 code) +{ + if(code==0xFFFF) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u", code); +} + +static void dmi_system_reset_timer(u16 code) +{ + if(code==0xFFFF) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %u min", code); +} + +/* + * 3.3.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]; +} + +/* + * 3.3.26 System Power Controls (Type 25) + */ + +static void dmi_power_controls_power_on(u8 *p) +{ + /* 3.3.26.1 */ + if(dmi_bcd_range(p[0], 0x01, 0x12)) + catsprintf(buffer, " %02X", p[0]); + else + catsprintf(buffer, " *"); + if(dmi_bcd_range(p[1], 0x01, 0x31)) + catsprintf(buffer, "-%02X", p[1]); + else + catsprintf(buffer, "-*"); + if(dmi_bcd_range(p[2], 0x00, 0x23)) + catsprintf(buffer, " %02X", p[2]); + else + catsprintf(buffer, " *"); + if(dmi_bcd_range(p[3], 0x00, 0x59)) + catsprintf(buffer, ":%02X", p[3]); + else + catsprintf(buffer, ":*"); + if(dmi_bcd_range(p[4], 0x00, 0x59)) + catsprintf(buffer, ":%02X", p[4]); + else + catsprintf(buffer, ":*"); +} + +/* + * 3.3.27 Voltage Probe (Type 26) + */ + +static const char *dmi_voltage_probe_location(u8 code) +{ + /* 3.3.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) +{ + /* 3.3.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) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %.3f V", (float)(i16)code/1000); +} + +static void dmi_voltage_probe_resolution(u16 code) +{ + if(code==0x8000) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %.1f mV", (float)code/10); +} + +static void dmi_probe_accuracy(u16 code) +{ + if(code==0x8000) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %.2f%%", (float)code/100); +} + +/* + * 3.3.28 Cooling Device (Type 27) + */ + +static const char *dmi_cooling_device_type(u8 code) +{ + /* 3.3.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, master.mif says 32 */ + "Passive Cooling" /* 0x11, master.mif says 33 */ + }; + + 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) + catsprintf(buffer, " Unknown Or Non-rotating"); + else + catsprintf(buffer, " %u rpm", code); +} + +/* + * 3.3.29 Temperature Probe (Type 28) + */ + +static const char *dmi_temperature_probe_location(u8 code) +{ + /* 3.3.29.1 */ + static const char *location[]={ + "Other", /* 0x01 */ + "Unknown", + "Processor", + "Disk", + "Peripheral Bay", + "System Management Module", /* master.mif says SMB Master */ + "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) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %.1f deg C", (float)(i16)code/10); +} + +static void dmi_temperature_probe_resolution(u16 code) +{ + if(code==0x8000) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %.3f deg C", (float)code/1000); +} + +/* + * 3.3.30 Electrical Current Probe (Type 29) + */ + +static void dmi_current_probe_value(u16 code) +{ + if(code==0x8000) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %.3f A", (float)(i16)code/1000); +} + +static void dmi_current_probe_resolution(u16 code) +{ + if(code==0x8000) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %.1f mA", (float)code/10); +} + +/* + * 3.3.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; +} + +/* + * 3.3.34 64-bit Memory Error Information (Type 33) + */ + +static void dmi_64bit_memory_error_address(u64 code) +{ + if(code.h==0x80000000 && code.l==0x00000000) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " 0x%08X%08X", code.h, code.l); +} + +/* + * 3.3.35 Management Device (Type 34) + */ + +static const char *dmi_management_device_type(u8 code) +{ + /* 3.3.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) +{ + /* 3.3.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; +} + +/* + * 3.3.38 Memory Channel (Type 37) + */ + +static const char *dmi_memory_channel_type(u8 code) +{ + /* 3.3.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, u8 *p, const char *prefix) +{ + int i; + + for(i=1; i<=count; i++) + { + catsprintf(buffer, "%sDevice %u Load: %u\n", + prefix, i, p[3*i]); + if(!(opt.flags & FLAG_QUIET)) + catsprintf(buffer, "%sDevice %u Handle: 0x%04X\n", + prefix, i, WORD(p+3*i+1)); + } +} + +/* + * 3.3.39 IPMI Device Information (Type 38) + */ + +static const char *dmi_ipmi_interface_type(u8 code) +{ + /* 3.3.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, u8 *p, u8 lsb) +{ + if(type==0x04) /* SSIF */ + { + catsprintf(buffer, "0x%02X (SMBus)", (*p)>>1); + } + else + { + u64 address=QWORD(p); + catsprintf(buffer, "0x%08X%08X (%s)", address.h, (address.l&~1)|lsb, + address.l&1?"I/O":"Memory-mapped"); + } +} + +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 */ + }; + + if(code<=0x02) + return spacing[code]; + return out_of_spec; +} + +/* + * 3.3.40 System Power Supply (Type 39) + */ + +static void dmi_power_supply_power(u16 code) +{ + if(code==0x8000) + catsprintf(buffer, " Unknown"); + else + catsprintf(buffer, " %.3f W", (float)code/1000); +} + +static const char *dmi_power_supply_type(u8 code) +{ + /* 3.3.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) +{ + /* 3.3.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) +{ + /* 3.3.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; +} + +/* + * Main + */ + +void dmi_decode(struct dmi_header *h, u16 ver) +{ + u8 *data=h->data; + + /* + * Note: DMI types 37 and 39 are untested + */ + switch(h->type) + { + case 0: /* 3.3.1 BIOS Information */ + catsprintf(buffer, "BIOS Information\n"); + if(h->length<0x12) break; + catsprintf(buffer, "\tVendor: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tVersion: %s\n", + dmi_string(h, data[0x05])); + catsprintf(buffer, "\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) + { + catsprintf(buffer, "\tAddress: 0x%04X0\n", + WORD(data+0x06)); + catsprintf(buffer, "\tRuntime Size:"); + dmi_bios_runtime_size((0x10000-WORD(data+0x06))<<4); + catsprintf(buffer, "\n"); + } + catsprintf(buffer, "\tROM Size: %u kB\n", + (data[0x09]+1)<<6); + catsprintf(buffer, "\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) + catsprintf(buffer, "\tBIOS Revision: %u.%u\n", + data[0x14], data[0x15]); + if(data[0x16]!=0xFF && data[0x17]!=0xFF) + catsprintf(buffer, "\tFirmware Revision: %u.%u\n", + data[0x16], data[0x17]); + break; + + case 1: /* 3.3.2 System Information */ + catsprintf(buffer, "System Information\n"); + if(h->length<0x08) break; + catsprintf(buffer, "\tManufacturer: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tProduct Name: %s\n", + dmi_string(h, data[0x05])); + catsprintf(buffer, "\tVersion: %s\n", + dmi_string(h, data[0x06])); + catsprintf(buffer, "\tSerial Number: %s\n", + dmi_string(h, data[0x07])); + if(h->length<0x19) break; + catsprintf(buffer, "\tUUID: "); + dmi_system_uuid(data+0x08); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tWake-up Type: %s\n", + dmi_system_wake_up_type(data[0x18])); + if(h->length<0x1B) break; + catsprintf(buffer, "\tSKU Number: %s\n", + dmi_string(h, data[0x19])); + catsprintf(buffer, "\tFamily: %s\n", + dmi_string(h, data[0x1A])); + break; + + case 2: /* 3.3.3 Base Board Information */ + catsprintf(buffer, "Base Board Information\n"); + if(h->length<0x08) break; + catsprintf(buffer, "\tManufacturer: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tProduct Name: %s\n", + dmi_string(h, data[0x05])); + catsprintf(buffer, "\tVersion: %s\n", + dmi_string(h, data[0x06])); + catsprintf(buffer, "\tSerial Number: %s\n", + dmi_string(h, data[0x07])); + if(h->length<0x0F) break; + catsprintf(buffer, "\tAsset Tag: %s\n", + dmi_string(h, data[0x08])); + catsprintf(buffer, "\tFeatures:"); + dmi_base_board_features(data[0x09], "\t\t"); + catsprintf(buffer, "\tLocation In Chassis: %s\n", + dmi_string(h, data[0x0A])); + if(!(opt.flags & FLAG_QUIET)) + catsprintf(buffer, "\tChassis Handle: 0x%04X\n", + WORD(data+0x0B)); + catsprintf(buffer, "\tType: %s\n", + dmi_base_board_type(data[0x0D])); + 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: /* 3.3.4 Chassis Information */ + catsprintf(buffer, "Chassis Information\n"); + if(h->length<0x09) break; + catsprintf(buffer, "\tManufacturer: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tType: %s\n", + dmi_chassis_type(data[0x05]&0x7F)); + catsprintf(buffer, "\tLock: %s\n", + dmi_chassis_lock(data[0x05]>>7)); + catsprintf(buffer, "\tVersion: %s\n", + dmi_string(h, data[0x06])); + catsprintf(buffer, "\tSerial Number: %s\n", + dmi_string(h, data[0x07])); + catsprintf(buffer, "\tAsset Tag: %s\n", + dmi_string(h, data[0x08])); + if(h->length<0x0D) break; + catsprintf(buffer, "\tBoot-up State: %s\n", + dmi_chassis_state(data[0x09])); + catsprintf(buffer, "\tPower Supply State: %s\n", + dmi_chassis_state(data[0x0A])); + catsprintf(buffer, "\tThermal State: %s\n", + dmi_chassis_state(data[0x0B])); + catsprintf(buffer, "\tSecurity Status: %s\n", + dmi_chassis_security_status(data[0x0C])); + if(h->length<0x11) break; + catsprintf(buffer, "\tOEM Information: 0x%08X\n", + DWORD(data+0x0D)); + if(h->length<0x15) break; + catsprintf(buffer, "\tHeight:"); + dmi_chassis_height(data[0x11]); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tNumber Of Power Cords:"); + dmi_chassis_power_cords(data[0x12]); + catsprintf(buffer, "\n"); + if(h->length<0x15+data[0x13]*data[0x14]) break; + dmi_chassis_elements(data[0x13], data[0x14], data+0x15, "\t"); + break; + + case 4: /* 3.3.5 Processor Information */ + catsprintf(buffer, "Processor Information\n"); + if(h->length<0x1A) break; + catsprintf(buffer, "\tSocket Designation: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tType: %s\n", + dmi_processor_type(data[0x05])); + catsprintf(buffer, "\tFamily: %s\n", + dmi_processor_family(data[0x06])); + catsprintf(buffer, "\tManufacturer: %s\n", + dmi_string(h, data[0x07])); + dmi_processor_id(data[0x06], data+8, dmi_string(h, data[0x10]), "\t"); + catsprintf(buffer, "\tVersion: %s\n", + dmi_string(h, data[0x10])); + catsprintf(buffer, "\tVoltage:"); + dmi_processor_voltage(data[0x11]); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tExternal Clock: "); + dmi_processor_frequency(data+0x12); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tMax Speed: "); + dmi_processor_frequency(data+0x14); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tCurrent Speed: "); + dmi_processor_frequency(data+0x16); + catsprintf(buffer, "\n"); + if(data[0x18]&(1<<6)) + catsprintf(buffer, "\tStatus: Populated, %s\n", + dmi_processor_status(data[0x18]&0x07)); + else + catsprintf(buffer, "\tStatus: Unpopulated\n"); + catsprintf(buffer, "\tUpgrade: %s\n", + dmi_processor_upgrade(data[0x19])); + if(h->length<0x20) break; + if(!(opt.flags & FLAG_QUIET)) + { + catsprintf(buffer, "\tL1 Cache Handle:"); + dmi_processor_cache(WORD(data+0x1A), "L1", ver); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tL2 Cache Handle:"); + dmi_processor_cache(WORD(data+0x1C), "L2", ver); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tL3 Cache Handle:"); + dmi_processor_cache(WORD(data+0x1E), "L3", ver); + catsprintf(buffer, "\n"); + } + if(h->length<0x23) break; + catsprintf(buffer, "\tSerial Number: %s\n", + dmi_string(h, data[0x20])); + catsprintf(buffer, "\tAsset Tag: %s\n", + dmi_string(h, data[0x21])); + catsprintf(buffer, "\tPart Number: %s\n", + dmi_string(h, data[0x22])); + if(h->length<0x28) break; + if(data[0x23]!=0) + catsprintf(buffer, "\tCore Count: %u\n", data[0x23]); + if(data[0x24]!=0) + catsprintf(buffer, "\tCore Enabled: %u\n", data[0x24]); + if(data[0x25]!=0) + catsprintf(buffer, "\tThread Count: %u\n", data[0x25]); + catsprintf(buffer, "\tCharacteristics:"); + dmi_processor_characteristics(WORD(data+0x26), "\t\t"); + break; + + case 5: /* 3.3.6 Memory Controller Information */ + catsprintf(buffer, "Memory Controller Information\n"); + if(h->length<0x0F) break; + catsprintf(buffer, "\tError Detecting Method: %s\n", + dmi_memory_controller_ed_method(data[0x04])); + catsprintf(buffer, "\tError Correcting Capabilities:"); + dmi_memory_controller_ec_capabilities(data[0x05], "\t\t"); + catsprintf(buffer, "\tSupported Interleave: %s\n", + dmi_memory_controller_interleave(data[0x06])); + catsprintf(buffer, "\tCurrent Interleave: %s\n", + dmi_memory_controller_interleave(data[0x07])); + catsprintf(buffer, "\tMaximum Memory Module Size: %u MB\n", + 1<<data[0x08]); + catsprintf(buffer, "\tMaximum Total Memory Size: %u MB\n", + data[0x0E]*(1<<data[0x08])); + catsprintf(buffer, "\tSupported Speeds:"); + dmi_memory_controller_speeds(WORD(data+0x09), "\t\t"); + catsprintf(buffer, "\tSupported Memory Types:"); + dmi_memory_module_types(WORD(data+0x0B), "\n\t\t"); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tMemory Module Voltage:"); + dmi_processor_voltage(data[0x0D]); + catsprintf(buffer, "\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; + catsprintf(buffer, "\tEnabled Error Correcting Capabilities:"); + dmi_memory_controller_ec_capabilities(data[0x0F+data[0x0E]*sizeof(u16)], "\t\t"); + break; + + case 6: /* 3.3.7 Memory Module Information */ + catsprintf(buffer, "Memory Module Information\n"); + if(h->length<0x0C) break; + catsprintf(buffer, "\tSocket Designation: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tBank Connections:"); + dmi_memory_module_connections(data[0x05]); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tCurrent Speed:"); + dmi_memory_module_speed(data[0x06]); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tType:"); + dmi_memory_module_types(WORD(data+0x07), " "); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tInstalled Size:"); + dmi_memory_module_size(data[0x09]); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tEnabled Size:"); + dmi_memory_module_size(data[0x0A]); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tError Status:"); + dmi_memory_module_error(data[0x0B], "\t\t"); + break; + + case 7: /* 3.3.8 Cache Information */ + catsprintf(buffer, "Cache Information\n"); + if(h->length<0x0F) break; + catsprintf(buffer, "\tSocket Designation: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tConfiguration: %s, %s, Level %u\n", + WORD(data+0x05)&0x0080?"Enabled":"Disabled", + WORD(data+0x05)&0x0008?"Socketed":"Not Socketed", + (WORD(data+0x05)&0x0007)+1); + catsprintf(buffer, "\tOperational Mode: %s\n", + dmi_cache_mode((WORD(data+0x05)>>8)&0x0003)); + catsprintf(buffer, "\tLocation: %s\n", + dmi_cache_location((WORD(data+0x05)>>5)&0x0003)); + catsprintf(buffer, "\tInstalled Size:"); + dmi_cache_size(WORD(data+0x09)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tMaximum Size:"); + dmi_cache_size(WORD(data+0x07)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tSupported SRAM Types:"); + dmi_cache_types(WORD(data+0x0B), "\n\t\t"); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tInstalled SRAM Type:"); + dmi_cache_types(WORD(data+0x0D), " "); + catsprintf(buffer, "\n"); + if(h->length<0x13) break; + catsprintf(buffer, "\tSpeed:"); + dmi_memory_module_speed(data[0x0F]); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tError Correction Type: %s\n", + dmi_cache_ec_type(data[0x10])); + catsprintf(buffer, "\tSystem Type: %s\n", + dmi_cache_type(data[0x11])); + catsprintf(buffer, "\tAssociativity: %s\n", + dmi_cache_associativity(data[0x12])); + break; + + case 8: /* 3.3.9 Port Connector Information */ + catsprintf(buffer, "Port Connector Information\n"); + if(h->length<0x09) break; + catsprintf(buffer, "\tInternal Reference Designator: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tInternal Connector Type: %s\n", + dmi_port_connector_type(data[0x05])); + catsprintf(buffer, "\tExternal Reference Designator: %s\n", + dmi_string(h, data[0x06])); + catsprintf(buffer, "\tExternal Connector Type: %s\n", + dmi_port_connector_type(data[0x07])); + catsprintf(buffer, "\tPort Type: %s\n", + dmi_port_type(data[0x08])); + break; + + case 9: /* 3.3.10 System Slots */ + catsprintf(buffer, "System Slot Information\n"); + if(h->length<0x0C) break; + catsprintf(buffer, "\tDesignation: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tType: %s%s\n", + dmi_slot_bus_width(data[0x06]), + dmi_slot_type(data[0x05])); + catsprintf(buffer, "\tCurrent Usage: %s\n", + dmi_slot_current_usage(data[0x07])); + catsprintf(buffer, "\tLength: %s\n", + dmi_slot_length(data[0x08])); + dmi_slot_id(data[0x09], data[0x0A], data[0x05], "\t"); + catsprintf(buffer, "\tCharacteristics:"); + if(h->length<0x0D) + dmi_slot_characteristics(data[0x0B], 0x00, "\t\t"); + else + dmi_slot_characteristics(data[0x0B], data[0x0C], "\t\t"); + break; + + case 10: /* 3.3.11 On Board Devices Information */ + dmi_on_board_devices(h, ""); + break; + + case 11: /* 3.3.12 OEM Strings */ + catsprintf(buffer, "OEM Strings\n"); + if(h->length<0x05) break; + dmi_oem_strings(h, "\t"); + break; + + case 12: /* 3.3.13 System Configuration Options */ + catsprintf(buffer, "System Configuration Options\n"); + if(h->length<0x05) break; + dmi_system_configuration_options(h, "\t"); + break; + + case 13: /* 3.3.14 BIOS Language Information */ + catsprintf(buffer, "BIOS Language Information\n"); + if(h->length<0x16) break; + catsprintf(buffer, "\tInstallable Languages: %u\n", data[0x04]); + dmi_bios_languages(h, "\t\t"); + catsprintf(buffer, "\tCurrently Installed Language: %s\n", + dmi_string(h, data[0x15])); + break; + + case 14: /* 3.3.15 Group Associations */ + catsprintf(buffer, "Group Associations\n"); + if(h->length<0x05) break; + catsprintf(buffer, "\tName: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tItems: %u\n", + (h->length-0x05)/3); + dmi_group_associations_items((h->length-0x05)/3, data+0x05, "\t\t"); + break; + + case 15: /* 3.3.16 System Event Log */ + catsprintf(buffer, "System Event Log\n"); + if(h->length<0x14) break; + catsprintf(buffer, "\tArea Length: %u bytes\n", + WORD(data+0x04)); + catsprintf(buffer, "\tHeader Start Offset: 0x%04X\n", + WORD(data+0x06)); + if(WORD(data+0x08)-WORD(data+0x06)) + catsprintf(buffer, "\tHeader Length: %u byte%s\n", + WORD(data+0x08)-WORD(data+0x06), + WORD(data+0x08)-WORD(data+0x06)>1?"s":""); + catsprintf(buffer, "\tData Start Offset: 0x%04X\n", + WORD(data+0x08)); + catsprintf(buffer, "\tAccess Method: %s\n", + dmi_event_log_method(data[0x0A])); + catsprintf(buffer, "\tAccess Address:"); + dmi_event_log_address(data[0x0A], data+0x10); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tStatus:"); + dmi_event_log_status(data[0x0B]); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tChange Token: 0x%08X\n", + DWORD(data+0x0C)); + if(h->length<0x17) break; + catsprintf(buffer, "\tHeader Format: %s\n", + dmi_event_log_header_type(data[0x14])); + catsprintf(buffer, "\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: /* 3.3.17 Physical Memory Array */ + catsprintf(buffer, "Physical Memory Array\n"); + if(h->length<0x0F) break; + catsprintf(buffer, "\tLocation: %s\n", + dmi_memory_array_location(data[0x04])); + catsprintf(buffer, "\tUse: %s\n", + dmi_memory_array_use(data[0x05])); + catsprintf(buffer, "\tError Correction Type: %s\n", + dmi_memory_array_ec_type(data[0x06])); + catsprintf(buffer, "\tMaximum Capacity:"); + dmi_memory_array_capacity(DWORD(data+0x07)); + catsprintf(buffer, "\n"); + if(!(opt.flags & FLAG_QUIET)) + { + catsprintf(buffer, "\tError Information Handle:"); + dmi_memory_array_error_handle(WORD(data+0x0B)); + catsprintf(buffer, "\n"); + } + catsprintf(buffer, "\tNumber Of Devices: %u\n", + WORD(data+0x0D)); + break; + + case 17: /* 3.3.18 Memory Device */ + catsprintf(buffer, "Memory Device\n"); + if(h->length<0x15) break; + if(!(opt.flags & FLAG_QUIET)) + { + catsprintf(buffer, "\tArray Handle: 0x%04X\n", + WORD(data+0x04)); + catsprintf(buffer, "\tError Information Handle:"); + dmi_memory_array_error_handle(WORD(data+0x06)); + catsprintf(buffer, "\n"); + } + catsprintf(buffer, "\tTotal Width:"); + dmi_memory_device_width(WORD(data+0x08)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tData Width:"); + dmi_memory_device_width(WORD(data+0x0A)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tSize:"); + dmi_memory_device_size(WORD(data+0x0C)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tForm Factor: %s\n", + dmi_memory_device_form_factor(data[0x0E])); + catsprintf(buffer, "\tSet:"); + dmi_memory_device_set(data[0x0F]); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tLocator: %s\n", + dmi_string(h, data[0x10])); + catsprintf(buffer, "\tBank Locator: %s\n", + dmi_string(h, data[0x11])); + catsprintf(buffer, "\tType: %s\n", + dmi_memory_device_type(data[0x12])); + catsprintf(buffer, "\tType Detail:"); + dmi_memory_device_type_detail(WORD(data+0x13)); + catsprintf(buffer, "\n"); + if(h->length<0x17) break; + catsprintf(buffer, "\tSpeed:"); + dmi_memory_device_speed(WORD(data+0x15)); + catsprintf(buffer, "\n"); + if(h->length<0x1B) break; + catsprintf(buffer, "\tManufacturer: %s\n", + dmi_string(h, data[0x17])); + catsprintf(buffer, "\tSerial Number: %s\n", + dmi_string(h, data[0x18])); + catsprintf(buffer, "\tAsset Tag: %s\n", + dmi_string(h, data[0x19])); + catsprintf(buffer, "\tPart Number: %s\n", + dmi_string(h, data[0x1A])); + break; + + case 18: /* 3.3.19 32-bit Memory Error Information */ + catsprintf(buffer, "32-bit Memory Error Information\n"); + if(h->length<0x17) break; + catsprintf(buffer, "\tType: %s\n", + dmi_memory_error_type(data[0x04])); + catsprintf(buffer, "\tGranularity: %s\n", + dmi_memory_error_granularity(data[0x05])); + catsprintf(buffer, "\tOperation: %s\n", + dmi_memory_error_operation(data[0x06])); + catsprintf(buffer, "\tVendor Syndrome:"); + dmi_memory_error_syndrome(DWORD(data+0x07)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tMemory Array Address:"); + dmi_32bit_memory_error_address(DWORD(data+0x0B)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tDevice Address:"); + dmi_32bit_memory_error_address(DWORD(data+0x0F)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tResolution:"); + dmi_32bit_memory_error_address(DWORD(data+0x13)); + catsprintf(buffer, "\n"); + break; + + case 19: /* 3.3.20 Memory Array Mapped Address */ + catsprintf(buffer, "Memory Array Mapped Address\n"); + if(h->length<0x0F) break; + catsprintf(buffer, "\tStarting Address: 0x%08X%03X\n", + DWORD(data+0x04)>>2, (DWORD(data+0x04)&0x3)<<10); + catsprintf(buffer, "\tEnding Address: 0x%08X%03X\n", + DWORD(data+0x08)>>2, ((DWORD(data+0x08)&0x3)<<10)+0x3FF); + catsprintf(buffer, "\tRange Size:"); + dmi_mapped_address_size(DWORD(data+0x08)-DWORD(data+0x04)+1); + catsprintf(buffer, "\n"); + if(!(opt.flags & FLAG_QUIET)) + catsprintf(buffer, "\tPhysical Array Handle: 0x%04X\n", + WORD(data+0x0C)); + catsprintf(buffer, "\tPartition Width: %u\n", + data[0x0F]); + break; + + case 20: /* 3.3.21 Memory Device Mapped Address */ + catsprintf(buffer, "Memory Device Mapped Address\n"); + if(h->length<0x13) break; + catsprintf(buffer, "\tStarting Address: 0x%08X%03X\n", + DWORD(data+0x04)>>2, (DWORD(data+0x04)&0x3)<<10); + catsprintf(buffer, "\tEnding Address: 0x%08X%03X\n", + DWORD(data+0x08)>>2, ((DWORD(data+0x08)&0x3)<<10)+0x3FF); + catsprintf(buffer, "\tRange Size:"); + dmi_mapped_address_size(DWORD(data+0x08)-DWORD(data+0x04)+1); + catsprintf(buffer, "\n"); + if(!(opt.flags & FLAG_QUIET)) + { + catsprintf(buffer, "\tPhysical Device Handle: 0x%04X\n", + WORD(data+0x0C)); + catsprintf(buffer, "\tMemory Array Mapped Address Handle: 0x%04X\n", + WORD(data+0x0E)); + } + catsprintf(buffer, "\tPartition Row Position:"); + dmi_mapped_address_row_position(data[0x10]); + catsprintf(buffer, "\n"); + dmi_mapped_address_interleave_position(data[0x11], "\t"); + dmi_mapped_address_interleaved_data_depth(data[0x12], "\t"); + break; + + case 21: /* 3.3.22 Built-in Pointing Device */ + catsprintf(buffer, "Built-in Pointing Device\n"); + if(h->length<0x07) break; + catsprintf(buffer, "\tType: %s\n", + dmi_pointing_device_type(data[0x04])); + catsprintf(buffer, "\tInterface: %s\n", + dmi_pointing_device_interface(data[0x05])); + catsprintf(buffer, "\tButtons: %u\n", + data[0x06]); + break; + + case 22: /* 3.3.23 Portable Battery */ + catsprintf(buffer, "Portable Battery\n"); + if(h->length<0x10) break; + catsprintf(buffer, "\tLocation: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tManufacturer: %s\n", + dmi_string(h, data[0x05])); + if(data[0x06] || h->length<0x1A) + catsprintf(buffer, "\tManufacture Date: %s\n", + dmi_string(h, data[0x06])); + if(data[0x07] || h->length<0x1A) + catsprintf(buffer, "\tSerial Number: %s\n", + dmi_string(h, data[0x07])); + catsprintf(buffer, "\tName: %s\n", + dmi_string(h, data[0x08])); + if(data[0x09]!=0x02 || h->length<0x1A) + catsprintf(buffer, "\tChemistry: %s\n", + dmi_battery_chemistry(data[0x09])); + catsprintf(buffer, "\tDesign Capacity:"); + if(h->length<0x1A) + dmi_battery_capacity(WORD(data+0x0A), 1); + else + dmi_battery_capacity(WORD(data+0x0A), data[0x15]); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tDesign Voltage:"); + dmi_battery_voltage(WORD(data+0x0C)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tSBDS Version: %s\n", + dmi_string(h, data[0x0E])); + catsprintf(buffer, "\tMaximum Error:"); + dmi_battery_maximum_error(data[0x0F]); + catsprintf(buffer, "\n"); + if(h->length<0x1A) break; + if(data[0x07]==0) + catsprintf(buffer, "\tSBDS Serial Number: %04X\n", + WORD(data+0x10)); + if(data[0x06]==0) + catsprintf(buffer, "\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) + catsprintf(buffer, "\tSBDS Chemistry: %s\n", + dmi_string(h, data[0x14])); + catsprintf(buffer, "\tOEM-specific Information: 0x%08X\n", + DWORD(data+0x16)); + break; + + case 23: /* 3.3.24 System Reset */ + catsprintf(buffer, "System Reset\n"); + if(h->length<0x0D) break; + catsprintf(buffer, "\tStatus: %s\n", + data[0x04]&(1<<0)?"Enabled":"Disabled"); + catsprintf(buffer, "\tWatchdog Timer: %s\n", + data[0x04]&(1<<5)?"Present":"Not Present"); + if(!(data[0x04]&(1<<5))) + break; + catsprintf(buffer, "\tBoot Option: %s\n", + dmi_system_reset_boot_option((data[0x04]>>1)&0x3)); + catsprintf(buffer, "\tBoot Option On Limit: %s\n", + dmi_system_reset_boot_option((data[0x04]>>3)&0x3)); + catsprintf(buffer, "\tReset Count:"); + dmi_system_reset_count(WORD(data+0x05)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tReset Limit:"); + dmi_system_reset_count(WORD(data+0x07)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tTimer Interval:"); + dmi_system_reset_timer(WORD(data+0x09)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tTimeout:"); + dmi_system_reset_timer(WORD(data+0x0B)); + catsprintf(buffer, "\n"); + break; + + case 24: /* 3.3.25 Hardware Security */ + catsprintf(buffer, "Hardware Security\n"); + if(h->length<0x05) break; + catsprintf(buffer, "\tPower-On Password Status: %s\n", + dmi_hardware_security_status(data[0x04]>>6)); + catsprintf(buffer, "\tKeyboard Password Status: %s\n", + dmi_hardware_security_status((data[0x04]>>4)&0x3)); + catsprintf(buffer, "\tAdministrator Password Status: %s\n", + dmi_hardware_security_status((data[0x04]>>2)&0x3)); + catsprintf(buffer, "\tFront Panel Reset Status: %s\n", + dmi_hardware_security_status(data[0x04]&0x3)); + break; + + case 25: /* 3.3.26 System Power Controls */ + catsprintf(buffer, "\tSystem Power Controls\n"); + if(h->length<0x09) break; + catsprintf(buffer, "\tNext Scheduled Power-on:"); + dmi_power_controls_power_on(data+0x04); + catsprintf(buffer, "\n"); + break; + + case 26: /* 3.3.27 Voltage Probe */ + catsprintf(buffer, "Voltage Probe\n"); + if(h->length<0x14) break; + catsprintf(buffer, "\tDescription: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tLocation: %s\n", + dmi_voltage_probe_location(data[0x05]&0x1f)); + catsprintf(buffer, "\tStatus: %s\n", + dmi_probe_status(data[0x05]>>5)); + catsprintf(buffer, "\tMaximum Value:"); + dmi_voltage_probe_value(WORD(data+0x06)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tMinimum Value:"); + dmi_voltage_probe_value(WORD(data+0x08)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tResolution:"); + dmi_voltage_probe_resolution(WORD(data+0x0A)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tTolerance:"); + dmi_voltage_probe_value(WORD(data+0x0C)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tAccuracy:"); + dmi_probe_accuracy(WORD(data+0x0E)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tOEM-specific Information: 0x%08X\n", + DWORD(data+0x10)); + if(h->length<0x16) break; + catsprintf(buffer, "\tNominal Value:"); + dmi_voltage_probe_value(WORD(data+0x14)); + catsprintf(buffer, "\n"); + break; + + case 27: /* 3.3.28 Cooling Device */ + catsprintf(buffer, "Cooling Device\n"); + if(h->length<0x0C) break; + if(!(opt.flags & FLAG_QUIET) && WORD(data+0x04)!=0xFFFF) + catsprintf(buffer, "\tTemperature Probe Handle: 0x%04X\n", + WORD(data+0x04)); + catsprintf(buffer, "\tType: %s\n", + dmi_cooling_device_type(data[0x06]&0x1f)); + catsprintf(buffer, "\tStatus: %s\n", + dmi_probe_status(data[0x06]>>5)); + if(data[0x07]!=0x00) + catsprintf(buffer, "\tCooling Unit Group: %u\n", + data[0x07]); + catsprintf(buffer, "\tOEM-specific Information: 0x%08X\n", + DWORD(data+0x08)); + if(h->length<0x0E) break; + catsprintf(buffer, "\tNominal Speed:"); + dmi_cooling_device_speed(WORD(data+0x0C)); + catsprintf(buffer, "\n"); + break; + + case 28: /* 3.3.29 Temperature Probe */ + catsprintf(buffer, "Temperature Probe\n"); + if(h->length<0x14) break; + catsprintf(buffer, "\tDescription: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tLocation: %s\n", + dmi_temperature_probe_location(data[0x05]&0x1F)); + catsprintf(buffer, "\tStatus: %s\n", + dmi_probe_status(data[0x05]>>5)); + catsprintf(buffer, "\tMaximum Value:"); + dmi_temperature_probe_value(WORD(data+0x06)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tMinimum Value"); + dmi_temperature_probe_value(WORD(data+0x08)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tResolution:"); + dmi_temperature_probe_resolution(WORD(data+0x0A)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tTolerance:"); + dmi_temperature_probe_value(WORD(data+0x0C)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tAccuracy:"); + dmi_probe_accuracy(WORD(data+0x0E)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tOEM-specific Information: 0x%08X\n", + DWORD(data+0x10)); + if(h->length<0x16) break; + catsprintf(buffer, "\tNominal Value:"); + dmi_temperature_probe_value(WORD(data+0x14)); + catsprintf(buffer, "\n"); + break; + + case 29: /* 3.3.30 Electrical Current Probe */ + catsprintf(buffer, "Electrical Current Probe\n"); + if(h->length<0x14) break; + catsprintf(buffer, "\tDescription: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tLocation: %s\n", + dmi_voltage_probe_location(data[5]&0x1F)); + catsprintf(buffer, "\tStatus: %s\n", + dmi_probe_status(data[0x05]>>5)); + catsprintf(buffer, "\tMaximum Value:"); + dmi_current_probe_value(WORD(data+0x06)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tMinimum Value:"); + dmi_current_probe_value(WORD(data+0x08)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tResolution:"); + dmi_current_probe_resolution(WORD(data+0x0A)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tTolerance:"); + dmi_current_probe_value(WORD(data+0x0C)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tAccuracy:"); + dmi_probe_accuracy(WORD(data+0x0E)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tOEM-specific Information: 0x%08X\n", + DWORD(data+0x10)); + if(h->length<0x16) break; + catsprintf(buffer, "\tNominal Value:"); + dmi_current_probe_value(WORD(data+0x14)); + catsprintf(buffer, "\n"); + break; + + case 30: /* 3.3.31 Out-of-band Remote Access */ + catsprintf(buffer, "Out-of-band Remote Access\n"); + if(h->length<0x06) break; + catsprintf(buffer, "\tManufacturer Name: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tInbound Connection: %s\n", + data[0x05]&(1<<0)?"Enabled":"Disabled"); + catsprintf(buffer, "\tOutbound Connection: %s\n", + data[0x05]&(1<<1)?"Enabled":"Disabled"); + break; + + case 31: /* 3.3.32 Boot Integrity Services Entry Point */ + catsprintf(buffer, "Boot Integrity Services Entry Point\n"); + break; + + case 32: /* 3.3.33 System Boot Information */ + catsprintf(buffer, "System Boot Information\n"); + if(h->length<0x0B) break; + catsprintf(buffer, "\tStatus: %s\n", + dmi_system_boot_status(data[0x0A])); + break; + + case 33: /* 3.3.34 64-bit Memory Error Information */ + if(h->length<0x1F) break; + catsprintf(buffer, "64-bit Memory Error Information\n"); + catsprintf(buffer, "\tType: %s\n", + dmi_memory_error_type(data[0x04])); + catsprintf(buffer, "\tGranularity: %s\n", + dmi_memory_error_granularity(data[0x05])); + catsprintf(buffer, "\tOperation: %s\n", + dmi_memory_error_operation(data[0x06])); + catsprintf(buffer, "\tVendor Syndrome:"); + dmi_memory_error_syndrome(DWORD(data+0x07)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tMemory Array Address:"); + dmi_64bit_memory_error_address(QWORD(data+0x0B)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tDevice Address:"); + dmi_64bit_memory_error_address(QWORD(data+0x13)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tResolution:"); + dmi_32bit_memory_error_address(DWORD(data+0x1B)); + catsprintf(buffer, "\n"); + break; + + case 34: /* 3.3.35 Management Device */ + catsprintf(buffer, "Management Device\n"); + if(h->length<0x0B) break; + catsprintf(buffer, "\tDescription: %s\n", + dmi_string(h, data[0x04])); + catsprintf(buffer, "\tType: %s\n", + dmi_management_device_type(data[0x05])); + catsprintf(buffer, "\tAddress: 0x%08X\n", + DWORD(data+0x06)); + catsprintf(buffer, "\tAddress Type: %s\n", + dmi_management_device_address_type(data[0x0A])); + break; + + case 35: /* 3.3.36 Management Device Component */ + catsprintf(buffer, "Management Device Component\n"); + if(h->length<0x0B) break; + catsprintf(buffer, "\tDescription: %s\n", + dmi_string(h, data[0x04])); + if(!(opt.flags & FLAG_QUIET)) + { + catsprintf(buffer, "\tManagement Device Handle: 0x%04X\n", + WORD(data+0x05)); + catsprintf(buffer, "\tComponent Handle: 0x%04X\n", + WORD(data+0x07)); + if(WORD(data+0x09)!=0xFFFF) + catsprintf(buffer, "\tThreshold Handle: 0x%04X\n", + WORD(data+0x09)); + } + break; + + case 36: /* 3.3.37 Management Device Threshold Data */ + catsprintf(buffer, "Management Device Threshold Data\n"); + if(h->length<0x10) break; + if(WORD(data+0x04)!=0x8000) + catsprintf(buffer, "\tLower Non-critical Threshold: %d\n", + (i16)WORD(data+0x04)); + if(WORD(data+0x06)!=0x8000) + catsprintf(buffer, "\tUpper Non-critical Threshold: %d\n", + (i16)WORD(data+0x06)); + if(WORD(data+0x08)!=0x8000) + catsprintf(buffer, "\tLower Critical Threshold: %d\n", + (i16)WORD(data+0x08)); + if(WORD(data+0x0A)!=0x8000) + catsprintf(buffer, "\tUpper Critical Threshold: %d\n", + (i16)WORD(data+0x0A)); + if(WORD(data+0x0C)!=0x8000) + catsprintf(buffer, "\tLower Non-recoverable Threshold: %d\n", + (i16)WORD(data+0x0C)); + if(WORD(data+0x0E)!=0x8000) + catsprintf(buffer, "\tUpper Non-recoverable Threshold: %d\n", + (i16)WORD(data+0x0E)); + break; + + case 37: /* 3.3.38 Memory Channel */ + catsprintf(buffer, "Memory Channel\n"); + if(h->length<0x07) break; + catsprintf(buffer, "\tType: %s\n", + dmi_memory_channel_type(data[0x04])); + catsprintf(buffer, "\tMaximal Load: %u\n", + data[0x05]); + catsprintf(buffer, "\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: /* 3.3.39 IPMI Device Information */ + /* + * We use the word "Version" instead of "Revision", conforming to + * the IPMI specification. + */ + catsprintf(buffer, "IPMI Device Information\n"); + if(h->length<0x10) break; + catsprintf(buffer, "\tInterface Type: %s\n", + dmi_ipmi_interface_type(data[0x04])); + catsprintf(buffer, "\tSpecification Version: %u.%u\n", + data[0x05]>>4, data[0x05]&0x0F); + catsprintf(buffer, "\tI2C Slave Address: 0x%02x\n", + data[0x06]>>1); + if(data[0x07]!=0xFF) + catsprintf(buffer, "\tNV Storage Device Address: %u\n", + data[0x07]); + else + catsprintf(buffer, "\tNV Storage Device: Not Present\n"); + catsprintf(buffer, "\tBase Address: "); + dmi_ipmi_base_address(data[0x04], data+0x08, + h->length<0x12?0:(data[0x10]>>5)&1); + catsprintf(buffer, "\n"); + if(h->length<0x12) break; + if(data[0x04]!=0x04) + { + catsprintf(buffer, "\tRegister Spacing: %s\n", + dmi_ipmi_register_spacing(data[0x10]>>6)); + if(data[0x10]&(1<<3)) + { + catsprintf(buffer, "\tInterrupt Polarity: %s\n", + data[0x10]&(1<<1)?"Active High":"Active Low"); + catsprintf(buffer, "\tInterrupt Trigger Mode: %s\n", + data[0x10]&(1<<0)?"Level":"Edge"); + } + } + if(data[0x11]!=0x00) + { + catsprintf(buffer, "\tInterrupt Number: %x\n", + data[0x11]); + } + break; + + case 39: /* 3.3.40 System Power Supply */ + catsprintf(buffer, "System Power Supply\n"); + if(h->length<0x10) break; + if(data[0x04]!=0x00) + catsprintf(buffer, "\tPower Unit Group: %u\n", + data[0x04]); + catsprintf(buffer, "\tLocation: %s\n", + dmi_string(h, data[0x05])); + catsprintf(buffer, "\tName: %s\n", + dmi_string(h, data[0x06])); + catsprintf(buffer, "\tManufacturer: %s\n", + dmi_string(h, data[0x07])); + catsprintf(buffer, "\tSerial Number: %s\n", + dmi_string(h, data[0x08])); + catsprintf(buffer, "\tAsset Tag: %s\n", + dmi_string(h, data[0x09])); + catsprintf(buffer, "\tModel Part Number: %s\n", + dmi_string(h, data[0x0A])); + catsprintf(buffer, "\tRevision: %s\n", + dmi_string(h, data[0x0B])); + catsprintf(buffer, "\tMax Power Capacity:"); + dmi_power_supply_power(WORD(data+0x0C)); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tStatus:"); + if(WORD(data+0x0E)&(1<<1)) + catsprintf(buffer, " Present, %s", + dmi_power_supply_status((WORD(data+0x0E)>>7)&0x07)); + else + catsprintf(buffer, " Not Present"); + catsprintf(buffer, "\n"); + catsprintf(buffer, "\tType: %s\n", + dmi_power_supply_type((WORD(data+0x0E)>>10)&0x0F)); + catsprintf(buffer, "\tInput Voltage Range Switching: %s\n", + dmi_power_supply_range_switching((WORD(data+0x0E)>>3)&0x0F)); + catsprintf(buffer, "\tPlugged: %s\n", + WORD(data+0x0E)&(1<<2)?"No":"Yes"); + catsprintf(buffer, "\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) + catsprintf(buffer, "\tInput Voltage Probe Handle: 0x%04X\n", + WORD(data+0x10)); + if(WORD(data+0x12)!=0xFFFF) + catsprintf(buffer, "\tCooling Device Handle: 0x%04X\n", + WORD(data+0x12)); + if(WORD(data+0x14)!=0xFFFF) + catsprintf(buffer, "\tInput Current Probe Handle: 0x%04X\n", + WORD(data+0x14)); + } + break; + + case 126: /* 3.3.41 Inactive */ + catsprintf(buffer, "Inactive\n"); + break; + + case 127: /* 3.3.42 End Of Table */ + catsprintf(buffer, "End Of Table\n"); + break; + + default: + if(dmi_decode_oem(h)) + break; + if(opt.flags & FLAG_QUIET) + return; + catsprintf(buffer, "%s Type\n", + h->type>=128?"OEM-specific":"Unknown"); + dmi_dump(h, "\t"); + } + catsprintf(buffer, "\n"); +} + +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(u32 base, u16 len, u16 num, u16 ver, const char *devmem) +{ + u8 *buf; + u8 *data; + int i=0; + + if(!(opt.flags & FLAG_QUIET)) + { + if(opt.type==NULL) + catsprintf(buffer, "%u structures occupying %u bytes.\n" + "Table at 0x%08X.\n", + num, len, base); + catsprintf(buffer, "\n"); + } + + if((buf=mem_chunk(base, len, devmem))==NULL) + { +#ifndef USE_MMAP + catsprintf(buffer, "Table is unreachable, sorry. Try compiling dmidecode with -DUSE_MMAP.\n"); +#endif + 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) + { + catsprintf(buffer, "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)) + catsprintf(buffer, "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"); + catsprintf(buffer, "\n"); + } + else + dmi_decode(&h, ver); + } + else if(!(opt.flags & FLAG_QUIET)) + catsprintf(buffer, "\t<TRUNCATED>\n\n"); + } + else if(opt.string!=NULL + && opt.string->type==h.type + && opt.string->offset<h.length) + { + if (opt.string->lookup!=NULL) + catsprintf(buffer, "%s\n", opt.string->lookup(data[opt.string->offset])); + else if (opt.string->print!=NULL) { + opt.string->print(data+opt.string->offset); + catsprintf(buffer, "\n"); + } + else + catsprintf(buffer, "%s\n", dmi_string(&h, data[opt.string->offset])); + } + + data=next; + i++; + } + + if(!(opt.flags & FLAG_QUIET)) + { + if(i!=num) + catsprintf(buffer, "Wrong DMI structures count: %d announced, " + "only %d decoded.\n", num, i); + if(data-buf!=len) + catsprintf(buffer, "Wrong DMI structures length: %d bytes " + "announced, structures occupy %d bytes.\n", + len, (unsigned int)(data-buf)); + } + + free(buf); +} + +int smbios_decode(u8 *buf, const char *devmem) +{ + if(checksum(buf, buf[0x05]) + && memcmp(buf+0x10, "_DMI_", 5)==0 + && checksum(buf+0x10, 0x0F)) + { + if(!(opt.flags & FLAG_QUIET)) + catsprintf(buffer, "SMBIOS %u.%u present.\n", + buf[0x06], buf[0x07]); + dmi_table(DWORD(buf+0x18), WORD(buf+0x16), WORD(buf+0x1C), + (buf[0x06]<<8)+buf[0x07], devmem); + return 1; + } + + return 0; +} + +int legacy_decode(u8 *buf, const char *devmem) +{ + if(checksum(buf, 0x0F)) + { + if(!(opt.flags & FLAG_QUIET)) + catsprintf(buffer, "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); + return 1; + } + + return 0; +} + +/* + * Probe for EFI interface + */ +#define EFI_NOT_FOUND (-1) +#define EFI_NO_SMBIOS (-2) +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)) + catsprintf(buffer, "# 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; +} + +#ifdef SO +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) + { + catsprintf(buffer, "%s\n", VERSION); + goto exit_free; + } + + if(!(opt.flags & FLAG_QUIET)) + catsprintf(buffer, "# dmidecode %s\n", VERSION); + + /* 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: + free(buf); + + if(!found && !(opt.flags & FLAG_QUIET)) + catsprintf(buffer, "# No SMBIOS nor DMI entry point found, sorry.\n"); + +exit_free: + free(opt.type); + + return ret; +} +#endif diff --git a/dmidecode.h b/dmidecode.h new file mode 100644 index 0000000..62779ca --- /dev/null +++ b/dmidecode.h @@ -0,0 +1,40 @@ +/* + * This file is part of the dmidecode project. + * + * (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 + */ + +struct dmi_header +{ + u8 type; + u8 length; + u16 handle; + u8 *data; +}; + +void dmi_dump(struct dmi_header *h, const char *prefix); +void dmi_decode(struct dmi_header *h, u16 ver); +int address_from_efi(size_t *address); +void to_dmi_header(struct dmi_header *h, u8 *data); +int smbios_decode(u8 *buf, const char *devmem); +int legacy_decode(u8 *buf, const char *devmem); + +const char *dmi_string(struct dmi_header *dm, u8 s); +void dmi_system_uuid(u8 *p); +const char *dmi_chassis_type(u8 code); +const char *dmi_processor_family(u8 code); +void dmi_processor_frequency(u8 *p); diff --git a/dmidecodemodule.c b/dmidecodemodule.c new file mode 100644 index 0000000..7590063 --- /dev/null +++ b/dmidecodemodule.c @@ -0,0 +1,170 @@ +#include <Python.h> + +#include <stdio.h> +#include <string.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 EFI_NOT_FOUND (-1) +#define EFI_NO_SMBIOS (-2) + +#include "catsprintf.h" +#include "global.h" + +//http://docs.python.org/api/sequence.html#l2h-338 +// NeuralNuts: you usually use PySquence_Fast() combined with +// PySquence_Fast_GET_ITEM, but since you know you have a tuple, +// PySequence_ITEM or PyTuple_GET_ITEM will be fine. +// +// +extern void dmi_dump(struct dmi_header *h, const char *prefix); +extern void dmi_decode(struct dmi_header *h, u16 ver); +extern int address_from_efi(size_t *address); +extern void to_dmi_header(struct dmi_header *h, u8 *data); +extern void dmi_table(u32 base, u16 len, u16 num, u16 ver, const char *devmem); +extern int smbios_decode(u8 *buf, const char *devmem); +extern int legacy_decode(u8 *buf, const char *devmem); +extern void *mem_chunk(size_t base, size_t len, const char *devmem); + +static PyObject* dmidecode_get(PyObject *self, PyObject *args) { + PyObject *list = PyList_New(0); + + //const char *command; + //if(!PyArg_ParseTuple(args, "s", &command)) + // return NULL; + + //for(i=0; i<len(args); i++) + // PyList_Append(list, Py_BuildValue("s", args[i])); + PyList_Append(list, PyInt_FromLong(3)); + PyList_Append(list, PyInt_FromLong(4)); + //PyList_Append(list, Py_BuildValue("s", command)); + PyList_Append(list, Py_BuildValue("i", PySequence_Size(args))); + + int i; + int argc = PySequence_Size(args); + char *argv[argc]; + for(i=0; i<argc; i++) { + argv[i] = PyString_AS_STRING(PySequence_ITEM(args, i)); + printf(">> %s <<\n", argv[i]); + PyList_Append(list, PySequence_ITEM(args, i)); + } + bzero(buffer, 50000); + //submain(buffer, argc, argv); + + return list; +} + +PyMethodDef DMIDataMethods[] = { + { "dmidecode", dmidecode_get, METH_VARARGS, "Get hardware data as a list" }, + { NULL, NULL, 0, NULL } +}; + + +PyMODINIT_FUNC initdmidecode(void) { + (void) Py_InitModule("dmidecode", DMIDataMethods); +} + + +int submain(char* buffer, 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); + + /* 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: + free(buf); + + if(!found && !(opt.flags & FLAG_QUIET)) + printf("# No SMBIOS nor DMI entry point found, sorry.\n"); + +exit_free: + free(opt.type); + + printf("%s\n", buffer); + return ret; +} diff --git a/dmioem.c b/dmioem.c new file mode 100644 index 0000000..a2fd2a2 --- /dev/null +++ b/dmioem.c @@ -0,0 +1,128 @@ +/* + * Decoding of OEM-specific entries + * This file is part of the dmidecode project. + * + * (C) 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 <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) + dmi_vendor=VENDOR_HP; +} + +/* + * HP-specific data structures are decoded here. + * + * Code contributed by John Cagle. + */ + +static int dmi_decode_hp(struct dmi_header *h) +{ + u8 *data=h->data; + int nic, ptr; + + switch(h->type) + { + case 204: + /* + * Vendor Specific: HP ProLiant System/Rack Locator + */ + printf("HP ProLiant System/Rack Locator\n"); + if(h->length<0x0B) break; + printf("\tRack Name: %s\n", dmi_string(h, data[0x04])); + printf("\tEnclosure Name: %s\n", dmi_string(h, data[0x05])); + printf("\tEnclosure Model: %s\n", dmi_string(h, data[0x06])); + printf("\tEnclosure Serial: %s\n", dmi_string(h, data[0x0A])); + printf("\tEnclosure Bays: %d\n", data[0x08]); + printf("\tServer Bay: %s\n", dmi_string(h, data[0x07])); + printf("\tBays Filled: %d\n", data[0x09]); + break; + + case 209: + case 221: + /* + * Vendor Specific: HP ProLiant NIC MAC Information + * + * This prints the BIOS NIC number, + * PCI bus/device/function, and MAC address + */ + printf(h->type==221? + "HP BIOS iSCSI NIC PCI and MAC Information\n": + "HP BIOS NIC PCI and MAC Information\n"); + nic=1; + ptr=4; + while(h->length>=ptr+8) + { + if(data[ptr]==0x00 && data[ptr+1]==0x00) + printf("\tNIC %d: Disabled\n", nic); + else if(data[ptr]==0xFF && data[ptr+1]==0xFF) + printf("\tNIC %d: Not Installed\n", nic); + else + { + printf("\tNIC %d: PCI device %02x:%02x.%x, " + "MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", + nic, data[ptr+1], data[ptr]>>3, data[ptr]&7, + data[ptr+2], data[ptr+3], + data[ptr+4], data[ptr+5], + data[ptr+6], data[ptr+7]); + } + nic++; + ptr+=8; + } + break; + + default: + return 0; + } + return 1; +} + +/* + * Dispatch vendor-specific entries decoding + * Return 1 if decoding was successful, 0 otherwise + */ +int dmi_decode_oem(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..00483f2 --- /dev/null +++ b/dmioem.h @@ -0,0 +1,25 @@ +/* + * Decoding of OEM-specific entries + * This file is part of the dmidecode project. + * + * (C) 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 + */ + +struct dmi_header; + +void dmi_set_vendor(const char *s); +int dmi_decode_oem(struct dmi_header *h); diff --git a/dmiopt.c b/dmiopt.c new file mode 100644 index 0000000..d571108 --- /dev/null +++ b/dmiopt.c @@ -0,0 +1,308 @@ +/* + * Command line handling of dmidecode + * This file is part of the dmidecode project. + * + * (C) 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 + */ + +#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, 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, NULL, NULL }, + { "bios-version", 0, 0x05, NULL, NULL }, + { "bios-release-date", 0, 0x08, NULL, NULL }, + { "system-manufacturer", 1, 0x04, NULL, NULL }, + { "system-product-name", 1, 0x05, NULL, NULL }, + { "system-version", 1, 0x06, NULL, NULL }, + { "system-serial-number", 1, 0x07, NULL, NULL }, + { "system-uuid", 1, 0x08, NULL, dmi_system_uuid }, + { "baseboard-manufacturer", 2, 0x04, NULL, NULL }, + { "baseboard-product-name", 2, 0x05, NULL, NULL }, + { "baseboard-version", 2, 0x06, NULL, NULL }, + { "baseboard-serial-number", 2, 0x07, NULL, NULL }, + { "baseboard-asset-tag", 2, 0x08, NULL, NULL }, + { "chassis-manufacturer", 3, 0x04, NULL, NULL }, + { "chassis-type", 3, 0x05, dmi_chassis_type, NULL }, + { "chassis-version", 3, 0x06, NULL, NULL }, + { "chassis-serial-number", 3, 0x07, NULL, NULL }, + { "chassis-asset-tag", 3, 0x08, NULL, NULL }, + { "processor-family", 4, 0x06, dmi_processor_family, NULL }, + { "processor-manufacturer", 4, 0x07, NULL, NULL }, + { "processor-version", 4, 0x10, NULL, NULL }, + { "processor-frequency", 4, 0x16, NULL, 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' }, + { "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 '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; + } + + if(opt.type!=NULL && opt.string!=NULL) + { + fprintf(stderr, "Options --string and --type are mutually exclusive\n"); + return -1; + } + + if((opt.flags & FLAG_DUMP) && opt.string!=NULL) + { + fprintf(stderr, "Options --string and --dump are mutually exclusive\n"); + return -1; + } + + if((opt.flags & FLAG_DUMP) && (opt.flags & FLAG_QUIET)) + { + fprintf(stderr, "Options --quiet and --dump 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" + " -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..fe8e193 --- /dev/null +++ b/dmiopt.h @@ -0,0 +1,46 @@ +/* + * Command line handling of dmidecode + * This file is part of the dmidecode project. + * + * (C) 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 + */ + +struct string_keyword +{ + const char *keyword; + u8 type; + u8 offset; + const char *(*lookup)(u8); + void (*print)(u8 *); +}; + +struct opt +{ + const char* devmem; + unsigned int flags; + u8 *type; + 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); diff --git a/global.h b/global.h new file mode 100644 index 0000000..a1a911a --- /dev/null +++ b/global.h @@ -0,0 +1,7 @@ +#ifndef GLOB +#define GLOB 1 + +struct opt opt; +char buffer[50000]; + +#endif diff --git a/ownership.c b/ownership.c new file mode 100644 index 0000000..29b9850 --- /dev/null +++ b/ownership.c @@ -0,0 +1,212 @@ +/* + * Compaq Ownership Tag + * + * (C) 2003-2005 Jean Delvare <khali@linux-fr.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open unpatent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + * + * References: + * - Compaq "Technical Reference Guide for Compaq Deskpro 4000 and 6000" + * First Edition + * http://h18000.www1.hp.com/support/techpubs/technical_reference_guides/113a1097.html + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> + +#include "version.h" +#include "config.h" +#include "types.h" +#include "util.h" + +/* Options are global */ +struct opt +{ + const char* devmem; + unsigned int flags; +}; +static struct opt opt; + +#define FLAG_VERSION (1<<0) +#define FLAG_HELP (1<<1) + +static void ownership(u32 base, const char *pname, const char *devmem) +{ + u8 *buf; + int i; + + /* read the ownership tag */ + if((buf=mem_chunk(base, 0x51, devmem))==NULL) + { + perror(pname); + return; + } + + /* chop the trailing garbage */ + i=0x4f; + while(i>=0 && (buf[i]==0x20 || buf[i]==0x00)) + i--; + buf[i+1]='\0'; + + /* filter and print */ + if(i>=0) + { + for(; i>=0; i--) + { + if(buf[i]<32 || (buf[i]>=127 && buf[i]<160)) + buf[i]='?'; + } + printf("%s\n", (char *)buf); + } + + free(buf); +} + +static u32 decode(const u8 *p) +{ + int i; + + /* integrity checking (lack of checksum) */ + for(i=0; i<p[4]; i++) + { + if(p[5+i*10]!='$' || !(p[6+i*10]>='A' && p[6+i*10]<='Z') + || !(p[7+i*10]>='A' && p[7+i*10]<='Z') + || !(p[8+i*10]>='A' && p[8+i*10]<='Z')) + { + printf("\t Abnormal Entry! Please report. [%02x %02x %02x %02x]\n", + p[5+i*10], p[6+i*10], p[7+i*10], p[8+i*10]); + return 0; + } + } + + /* search for the right entry */ + for(i=0; i<p[4]; i++) + if(memcmp(p+5+i*10, "$ERB", 4)==0) + return DWORD(p+9+i*10); + + return 0; +} + +/* Return -1 on error, 0 on success */ +static int parse_command_line(int argc, char * const argv[]) +{ + int option; + const char *optstring = "d:hV"; + struct option longopts[]={ + { "dev-mem", required_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { 0, 0, 0, 0 } + }; + + while((option=getopt_long(argc, argv, optstring, longopts, NULL))!=-1) + switch(option) + { + case 'd': + opt.devmem=optarg; + break; + case 'h': + opt.flags|=FLAG_HELP; + break; + case 'V': + opt.flags|=FLAG_VERSION; + break; + case '?': + return -1; + } + + return 0; +} + +static void print_help(void) +{ + static const char *help= + "Usage: ownership [OPTIONS]\n" + "Options are:\n" + " -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n" + " -h, --help Display this help text and exit\n" + " -V, --version Display the version and exit\n"; + + printf("%s", help); +} + +int main(int argc, char * const argv[]) +{ + u8 *buf; + off_t fp; + int ok=0; + + if(sizeof(u8)!=1 || sizeof(u32)!=4) + { + fprintf(stderr, "%s: compiler incompatibility\n", argv[0]); + exit(255); + } + + /* Set default option values */ + opt.devmem=DEFAULT_MEM_DEV; + opt.flags=0; + + if(parse_command_line(argc, argv)<0) + exit(2); + + if(opt.flags & FLAG_HELP) + { + print_help(); + return 0; + } + + if(opt.flags & FLAG_VERSION) + { + printf("%s\n", VERSION); + return 0; + } + + if((buf=mem_chunk(0xE0000, 0x20000, opt.devmem))==NULL) + exit(1); + + for(fp=0; !ok && fp<=0x1FFF0; fp+=16) + { + u8 *p=buf+fp; + + if(memcmp((char *)p, "32OS", 4)==0) + { + off_t len=p[4]*10+5; + + if(fp+len-1<=0x1FFFF) + { + u32 base; + + if((base=decode(p))) + { + ok=1; + ownership(base, argv[0], opt.devmem); + } + } + } + } + + free(buf); + + return 0; +} diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..ca193c0 --- /dev/null +++ b/setup.py @@ -0,0 +1,5 @@ +from distutils.core import setup, Extension + +setup(name = "DMIDecode", + version = "1.0", + ext_modules = [Extension("dmidecode", ["dmidecodemodule.c"])]) @@ -0,0 +1,127 @@ +#include <stdio.h> +#include <string.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 EFI_NOT_FOUND (-1) +#define EFI_NO_SMBIOS (-2) + +#include <Python.h> +#include "catsprintf.h" +#include "global.h" + +extern void dmi_dump(struct dmi_header *h, const char *prefix); +extern void dmi_decode(struct dmi_header *h, u16 ver); +extern int address_from_efi(size_t *address); +extern void to_dmi_header(struct dmi_header *h, u8 *data); +extern void dmi_table(u32 base, u16 len, u16 num, u16 ver, const char *devmem); +extern int smbios_decode(u8 *buf, const char *devmem); +extern int legacy_decode(u8 *buf, const char *devmem); + + + +int main(int argc, char * const argv[]) +{ + bzero(buffer, 50000); + + 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); + + /* 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: + free(buf); + + if(!found && !(opt.flags & FLAG_QUIET)) + printf("# No SMBIOS nor DMI entry point found, sorry.\n"); + +exit_free: + free(opt.type); + + printf("%s\n", buffer); + return ret; +} @@ -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,165 @@ +/* + * Common "util" functions + * This file is part of the dmidecode project. + * + * (C) 2002-2005 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" + +#ifndef USE_MMAP +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; +} +#endif + +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) + { + fprintf(stderr, "%s: ", devmem); + perror("mmap"); + free(p); + return NULL; + } + + memcpy(p, (u8 *)mmp+mmoffset, len); + + if(munmap(mmp, mmoffset+len)==-1) + { + fprintf(stderr, "%s: ", devmem); + perror("munmap"); + } +#else /* USE_MMAP */ + 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; + } +#endif /* USE_MMAP */ + + if(close(fd)==-1) + perror(devmem); + + return p; +} @@ -0,0 +1,8 @@ +#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); diff --git a/version.h b/version.h new file mode 100644 index 0000000..050cf7a --- /dev/null +++ b/version.h @@ -0,0 +1 @@ +#define VERSION "2.9" diff --git a/vpddecode.c b/vpddecode.c new file mode 100644 index 0000000..4e00263 --- /dev/null +++ b/vpddecode.c @@ -0,0 +1,202 @@ +/* + * IBM Vital Product Data decoder + * + * (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: + * - 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! Please report.\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 (Please report!)\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), please report!\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..c895202 --- /dev/null +++ b/vpdopt.c @@ -0,0 +1,159 @@ +/* + * Command line handling of vpddecode + * This file is part of the dmidecode project. + * + * (C) 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 + */ + +#include <stdio.h> +#include <strings.h> +#include <stdlib.h> +#include <getopt.h> + +#include "config.h" +#include "util.h" +#include "vpdopt.h" + +#include "global.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..378766f --- /dev/null +++ b/vpdopt.h @@ -0,0 +1,45 @@ +/* + * Command line handling of vpddecode + * This file is part of the dmidecode project. + * + * (C) 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 + */ + +#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); |