"Fossies" - the Fresh Open Source Software Archive

Member "dmidecode-3.3/dmidecode.c" (14 Oct 2020, 138717 Bytes) of package /linux/privat/dmidecode-3.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dmidecode.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.2_vs_3.3.

    1 /*
    2  * DMI Decode
    3  *
    4  *   Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
    5  *   Copyright (C) 2002-2020 Jean Delvare <jdelvare@suse.de>
    6  *
    7  *   This program is free software; you can redistribute it and/or modify
    8  *   it under the terms of the GNU General Public License as published by
    9  *   the Free Software Foundation; either version 2 of the License, or
   10  *   (at your option) any later version.
   11  *
   12  *   This program is distributed in the hope that it will be useful,
   13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  *   GNU General Public License for more details.
   16  *
   17  *   You should have received a copy of the GNU General Public License
   18  *   along with this program; if not, write to the Free Software
   19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   20  *
   21  *   For the avoidance of doubt the "preferred form" of this code is one which
   22  *   is in an open unpatent encumbered format. Where cryptographic key signing
   23  *   forms part of the process of creating an executable the information
   24  *   including keys needed to generate an equivalently functional executable
   25  *   are deemed to be part of the source code.
   26  *
   27  * Unless specified otherwise, all references are aimed at the "System
   28  * Management BIOS Reference Specification, Version 3.2.0" document,
   29  * available from http://www.dmtf.org/standards/smbios.
   30  *
   31  * Note to contributors:
   32  * Please reference every value you add or modify, especially if the
   33  * information does not come from the above mentioned specification.
   34  *
   35  * Additional references:
   36  *  - Intel AP-485 revision 36
   37  *    "Intel Processor Identification and the CPUID Instruction"
   38  *    http://www.intel.com/support/processors/sb/cs-009861.htm
   39  *  - DMTF Common Information Model
   40  *    CIM Schema version 2.19.1
   41  *    http://www.dmtf.org/standards/cim/
   42  *  - IPMI 2.0 revision 1.0
   43  *    "Intelligent Platform Management Interface Specification"
   44  *    http://developer.intel.com/design/servers/ipmi/spec.htm
   45  *  - AMD publication #25481 revision 2.28
   46  *    "CPUID Specification"
   47  *    http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf
   48  *  - BIOS Integrity Services Application Programming Interface version 1.0
   49  *    http://www.intel.com/design/archives/wfm/downloads/bisspec.htm
   50  *  - DMTF DSP0239 version 1.1.0
   51  *    "Management Component Transport Protocol (MCTP) IDs and Codes"
   52  *    http://www.dmtf.org/standards/pmci
   53  *  - "TPM Main, Part 2 TPM Structures"
   54  *    Specification version 1.2, level 2, revision 116
   55  *    https://trustedcomputinggroup.org/tpm-main-specification/
   56  *  - "PC Client Platform TPM Profile (PTP) Specification"
   57  *    Family "2.0", Level 00, Revision 00.43, January 26, 2015
   58  *    https://trustedcomputinggroup.org/pc-client-platform-tpm-profile-ptp-specification/
   59  *  - "RedFish Host Interface Specification" (DMTF DSP0270)
   60  *    https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf
   61  */
   62 
   63 #include <stdio.h>
   64 #include <string.h>
   65 #include <strings.h>
   66 #include <stdlib.h>
   67 #include <unistd.h>
   68 #include <arpa/inet.h>
   69 #include <sys/socket.h>
   70 
   71 #ifdef __FreeBSD__
   72 #include <errno.h>
   73 #include <kenv.h>
   74 #endif
   75 
   76 #include "version.h"
   77 #include "config.h"
   78 #include "types.h"
   79 #include "util.h"
   80 #include "dmidecode.h"
   81 #include "dmiopt.h"
   82 #include "dmioem.h"
   83 #include "dmioutput.h"
   84 
   85 #define out_of_spec "<OUT OF SPEC>"
   86 static const char *bad_index = "<BAD INDEX>";
   87 
   88 #define SUPPORTED_SMBIOS_VER 0x030300
   89 
   90 #define FLAG_NO_FILE_OFFSET     (1 << 0)
   91 #define FLAG_STOP_AT_EOT        (1 << 1)
   92 
   93 #define SYS_FIRMWARE_DIR "/sys/firmware/dmi/tables"
   94 #define SYS_ENTRY_FILE SYS_FIRMWARE_DIR "/smbios_entry_point"
   95 #define SYS_TABLE_FILE SYS_FIRMWARE_DIR "/DMI"
   96 
   97 /*
   98  * Type-independant Stuff
   99  */
  100 
  101 /* Returns 1 if the buffer contains only printable ASCII characters */
  102 int is_printable(const u8 *data, int len)
  103 {
  104     int i;
  105 
  106     for (i = 0; i < len; i++)
  107         if (data[i] < 32 || data[i] >= 127)
  108             return 0;
  109 
  110     return 1;
  111 }
  112 
  113 /* Replace non-ASCII characters with dots */
  114 static void ascii_filter(char *bp, size_t len)
  115 {
  116     size_t i;
  117 
  118     for (i = 0; i < len; i++)
  119         if (bp[i] < 32 || bp[i] == 127)
  120             bp[i] = '.';
  121 }
  122 
  123 static char *_dmi_string(const struct dmi_header *dm, u8 s, int filter)
  124 {
  125     char *bp = (char *)dm->data;
  126 
  127     bp += dm->length;
  128     while (s > 1 && *bp)
  129     {
  130         bp += strlen(bp);
  131         bp++;
  132         s--;
  133     }
  134 
  135     if (!*bp)
  136         return NULL;
  137 
  138     if (filter)
  139         ascii_filter(bp, strlen(bp));
  140 
  141     return bp;
  142 }
  143 
  144 const char *dmi_string(const struct dmi_header *dm, u8 s)
  145 {
  146     char *bp;
  147 
  148     if (s == 0)
  149         return "Not Specified";
  150 
  151     bp = _dmi_string(dm, s, 1);
  152     if (bp == NULL)
  153         return bad_index;
  154 
  155     return bp;
  156 }
  157 
  158 static const char *dmi_smbios_structure_type(u8 code)
  159 {
  160     static const char *type[] = {
  161         "BIOS", /* 0 */
  162         "System",
  163         "Base Board",
  164         "Chassis",
  165         "Processor",
  166         "Memory Controller",
  167         "Memory Module",
  168         "Cache",
  169         "Port Connector",
  170         "System Slots",
  171         "On Board Devices",
  172         "OEM Strings",
  173         "System Configuration Options",
  174         "BIOS Language",
  175         "Group Associations",
  176         "System Event Log",
  177         "Physical Memory Array",
  178         "Memory Device",
  179         "32-bit Memory Error",
  180         "Memory Array Mapped Address",
  181         "Memory Device Mapped Address",
  182         "Built-in Pointing Device",
  183         "Portable Battery",
  184         "System Reset",
  185         "Hardware Security",
  186         "System Power Controls",
  187         "Voltage Probe",
  188         "Cooling Device",
  189         "Temperature Probe",
  190         "Electrical Current Probe",
  191         "Out-of-band Remote Access",
  192         "Boot Integrity Services",
  193         "System Boot",
  194         "64-bit Memory Error",
  195         "Management Device",
  196         "Management Device Component",
  197         "Management Device Threshold Data",
  198         "Memory Channel",
  199         "IPMI Device",
  200         "Power Supply",
  201         "Additional Information",
  202         "Onboard Device",
  203         "Management Controller Host Interface",
  204         "TPM Device", /* 43 */
  205     };
  206 
  207     if (code >= 128)
  208         return "OEM-specific";
  209     if (code <= 43)
  210         return type[code];
  211     return out_of_spec;
  212 }
  213 
  214 static int dmi_bcd_range(u8 value, u8 low, u8 high)
  215 {
  216     if (value > 0x99 || (value & 0x0F) > 0x09)
  217         return 0;
  218     if (value < low || value > high)
  219         return 0;
  220     return 1;
  221 }
  222 
  223 static void dmi_dump(const struct dmi_header *h)
  224 {
  225     static char raw_data[48];
  226     int row, i;
  227     unsigned int off;
  228     char *s;
  229 
  230     pr_list_start("Header and Data", NULL);
  231     for (row = 0; row < ((h->length - 1) >> 4) + 1; row++)
  232     {
  233         off = 0;
  234         for (i = 0; i < 16 && i < h->length - (row << 4); i++)
  235             off += sprintf(raw_data + off, i ? " %02X" : "%02X",
  236                    (h->data)[(row << 4) + i]);
  237         pr_list_item(raw_data);
  238     }
  239     pr_list_end();
  240 
  241     if ((h->data)[h->length] || (h->data)[h->length + 1])
  242     {
  243         pr_list_start("Strings", NULL);
  244         i = 1;
  245         while ((s = _dmi_string(h, i++, !(opt.flags & FLAG_DUMP))))
  246         {
  247             if (opt.flags & FLAG_DUMP)
  248             {
  249                 int j, l = strlen(s) + 1;
  250 
  251                 off = 0;
  252                 for (row = 0; row < ((l - 1) >> 4) + 1; row++)
  253                 {
  254                     for (j = 0; j < 16 && j < l - (row << 4); j++)
  255                         off += sprintf(raw_data + off,
  256                                j ? " %02X" : "%02X",
  257                                (unsigned char)s[(row << 4) + j]);
  258                     pr_list_item(raw_data);
  259                 }
  260                 /* String isn't filtered yet so do it now */
  261                 ascii_filter(s, l - 1);
  262             }
  263             pr_list_item("%s", s);
  264         }
  265         pr_list_end();
  266     }
  267 }
  268 
  269 /* shift is 0 if the value is in bytes, 1 if it is in kilobytes */
  270 static void dmi_print_memory_size(const char *attr, u64 code, int shift)
  271 {
  272     unsigned long capacity;
  273     u16 split[7];
  274     static const char *unit[8] = {
  275         "bytes", "kB", "MB", "GB", "TB", "PB", "EB", "ZB"
  276     };
  277     int i;
  278 
  279     /*
  280      * We split the overall size in powers of thousand: EB, PB, TB, GB,
  281      * MB, kB and B. In practice, it is expected that only one or two
  282      * (consecutive) of these will be non-zero.
  283      */
  284     split[0] = code.l & 0x3FFUL;
  285     split[1] = (code.l >> 10) & 0x3FFUL;
  286     split[2] = (code.l >> 20) & 0x3FFUL;
  287     split[3] = ((code.h << 2) & 0x3FCUL) | (code.l >> 30);
  288     split[4] = (code.h >> 8) & 0x3FFUL;
  289     split[5] = (code.h >> 18) & 0x3FFUL;
  290     split[6] = code.h >> 28;
  291 
  292     /*
  293      * Now we find the highest unit with a non-zero value. If the following
  294      * is also non-zero, we use that as our base. If the following is zero,
  295      * we simply display the highest unit.
  296      */
  297     for (i = 6; i > 0; i--)
  298     {
  299         if (split[i])
  300             break;
  301     }
  302     if (i > 0 && split[i - 1])
  303     {
  304         i--;
  305         capacity = split[i] + (split[i + 1] << 10);
  306     }
  307     else
  308         capacity = split[i];
  309 
  310     pr_attr(attr, "%lu %s", capacity, unit[i + shift]);
  311 }
  312 
  313 /*
  314  * 7.1 BIOS Information (Type 0)
  315  */
  316 
  317 static void dmi_bios_runtime_size(u32 code)
  318 {
  319     const char *format;
  320 
  321     if (code & 0x000003FF)
  322     {
  323         format = "%u bytes";
  324     }
  325     else
  326     {
  327         format = "%u kB";
  328         code >>= 10;
  329     }
  330 
  331     pr_attr("Runtime Size", format, code);
  332 }
  333 
  334 static void dmi_bios_rom_size(u8 code1, u16 code2)
  335 {
  336     static const char *unit[4] = {
  337         "MB", "GB", out_of_spec, out_of_spec
  338     };
  339 
  340     if (code1 != 0xFF)
  341     {
  342         u64 s = { .l = (code1 + 1) << 6 };
  343         dmi_print_memory_size("ROM Size", s, 1);
  344     }
  345     else
  346         pr_attr("ROM Size", "%u %s", code2 & 0x3FFF, unit[code2 >> 14]);
  347 }
  348 
  349 static void dmi_bios_characteristics(u64 code)
  350 {
  351     /* 7.1.1 */
  352     static const char *characteristics[] = {
  353         "BIOS characteristics not supported", /* 3 */
  354         "ISA is supported",
  355         "MCA is supported",
  356         "EISA is supported",
  357         "PCI is supported",
  358         "PC Card (PCMCIA) is supported",
  359         "PNP is supported",
  360         "APM is supported",
  361         "BIOS is upgradeable",
  362         "BIOS shadowing is allowed",
  363         "VLB is supported",
  364         "ESCD support is available",
  365         "Boot from CD is supported",
  366         "Selectable boot is supported",
  367         "BIOS ROM is socketed",
  368         "Boot from PC Card (PCMCIA) is supported",
  369         "EDD is supported",
  370         "Japanese floppy for NEC 9800 1.2 MB is supported (int 13h)",
  371         "Japanese floppy for Toshiba 1.2 MB is supported (int 13h)",
  372         "5.25\"/360 kB floppy services are supported (int 13h)",
  373         "5.25\"/1.2 MB floppy services are supported (int 13h)",
  374         "3.5\"/720 kB floppy services are supported (int 13h)",
  375         "3.5\"/2.88 MB floppy services are supported (int 13h)",
  376         "Print screen service is supported (int 5h)",
  377         "8042 keyboard services are supported (int 9h)",
  378         "Serial services are supported (int 14h)",
  379         "Printer services are supported (int 17h)",
  380         "CGA/mono video services are supported (int 10h)",
  381         "NEC PC-98" /* 31 */
  382     };
  383     int i;
  384 
  385     /*
  386      * This isn't very clear what this bit is supposed to mean
  387      */
  388     if (code.l & (1 << 3))
  389     {
  390         pr_list_item("%s", characteristics[0]);
  391         return;
  392     }
  393 
  394     for (i = 4; i <= 31; i++)
  395         if (code.l & (1 << i))
  396             pr_list_item("%s", characteristics[i - 3]);
  397 }
  398 
  399 static void dmi_bios_characteristics_x1(u8 code)
  400 {
  401     /* 7.1.2.1 */
  402     static const char *characteristics[] = {
  403         "ACPI is supported", /* 0 */
  404         "USB legacy is supported",
  405         "AGP is supported",
  406         "I2O boot is supported",
  407         "LS-120 boot is supported",
  408         "ATAPI Zip drive boot is supported",
  409         "IEEE 1394 boot is supported",
  410         "Smart battery is supported" /* 7 */
  411     };
  412     int i;
  413 
  414     for (i = 0; i <= 7; i++)
  415         if (code & (1 << i))
  416             pr_list_item("%s", characteristics[i]);
  417 }
  418 
  419 static void dmi_bios_characteristics_x2(u8 code)
  420 {
  421     /* 37.1.2.2 */
  422     static const char *characteristics[] = {
  423         "BIOS boot specification is supported", /* 0 */
  424         "Function key-initiated network boot is supported",
  425         "Targeted content distribution is supported",
  426         "UEFI is supported",
  427         "System is a virtual machine" /* 4 */
  428     };
  429     int i;
  430 
  431     for (i = 0; i <= 4; i++)
  432         if (code & (1 << i))
  433             pr_list_item("%s", characteristics[i]);
  434 }
  435 
  436 /*
  437  * 7.2 System Information (Type 1)
  438  */
  439 
  440 static void dmi_system_uuid(void (*print_cb)(const char *name, const char *format, ...),
  441                 const char *attr, const u8 *p, u16 ver)
  442 {
  443     int only0xFF = 1, only0x00 = 1;
  444     int i;
  445 
  446     for (i = 0; i < 16 && (only0x00 || only0xFF); i++)
  447     {
  448         if (p[i] != 0x00) only0x00 = 0;
  449         if (p[i] != 0xFF) only0xFF = 0;
  450     }
  451 
  452     if (only0xFF)
  453     {
  454         if (print_cb)
  455             print_cb(attr, "Not Present");
  456         else
  457             printf("Not Present\n");
  458         return;
  459     }
  460     if (only0x00)
  461     {
  462         if (print_cb)
  463             print_cb(attr, "Not Settable");
  464         else
  465             printf("Not Settable\n");
  466         return;
  467     }
  468 
  469     /*
  470      * As of version 2.6 of the SMBIOS specification, the first 3
  471      * fields of the UUID are supposed to be encoded on little-endian.
  472      * The specification says that this is the defacto standard,
  473      * however I've seen systems following RFC 4122 instead and use
  474      * network byte order, so I am reluctant to apply the byte-swapping
  475      * for older versions.
  476      */
  477     if (ver >= 0x0206)
  478     {
  479         if (print_cb)
  480             print_cb(attr,
  481                 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  482                 p[3], p[2], p[1], p[0], p[5], p[4], p[7], p[6],
  483                 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
  484         else
  485             printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
  486                 p[3], p[2], p[1], p[0], p[5], p[4], p[7], p[6],
  487                 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
  488     }
  489     else
  490     {
  491         if (print_cb)
  492             print_cb(attr,
  493                 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  494                 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
  495                 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
  496         else
  497             printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
  498                 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
  499                 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
  500     }
  501 }
  502 
  503 static const char *dmi_system_wake_up_type(u8 code)
  504 {
  505     /* 7.2.2 */
  506     static const char *type[] = {
  507         "Reserved", /* 0x00 */
  508         "Other",
  509         "Unknown",
  510         "APM Timer",
  511         "Modem Ring",
  512         "LAN Remote",
  513         "Power Switch",
  514         "PCI PME#",
  515         "AC Power Restored" /* 0x08 */
  516     };
  517 
  518     if (code <= 0x08)
  519         return type[code];
  520     return out_of_spec;
  521 }
  522 
  523 /*
  524  * 7.3 Base Board Information (Type 2)
  525  */
  526 
  527 static void dmi_base_board_features(u8 code)
  528 {
  529     /* 7.3.1 */
  530     static const char *features[] = {
  531         "Board is a hosting board", /* 0 */
  532         "Board requires at least one daughter board",
  533         "Board is removable",
  534         "Board is replaceable",
  535         "Board is hot swappable" /* 4 */
  536     };
  537 
  538     if ((code & 0x1F) == 0)
  539         pr_list_start("Features", "%s", "None");
  540     else
  541     {
  542         int i;
  543 
  544         pr_list_start("Features", NULL);
  545         for (i = 0; i <= 4; i++)
  546             if (code & (1 << i))
  547                 pr_list_item("%s", features[i]);
  548     }
  549     pr_list_end();
  550 }
  551 
  552 static const char *dmi_base_board_type(u8 code)
  553 {
  554     /* 7.3.2 */
  555     static const char *type[] = {
  556         "Unknown", /* 0x01 */
  557         "Other",
  558         "Server Blade",
  559         "Connectivity Switch",
  560         "System Management Module",
  561         "Processor Module",
  562         "I/O Module",
  563         "Memory Module",
  564         "Daughter Board",
  565         "Motherboard",
  566         "Processor+Memory Module",
  567         "Processor+I/O Module",
  568         "Interconnect Board" /* 0x0D */
  569     };
  570 
  571     if (code >= 0x01 && code <= 0x0D)
  572         return type[code - 0x01];
  573     return out_of_spec;
  574 }
  575 
  576 static void dmi_base_board_handles(u8 count, const u8 *p)
  577 {
  578     int i;
  579 
  580     pr_list_start("Contained Object Handles", "%u", count);
  581     for (i = 0; i < count; i++)
  582         pr_list_item("0x%04X", WORD(p + sizeof(u16) * i));
  583     pr_list_end();
  584 }
  585 
  586 /*
  587  * 7.4 Chassis Information (Type 3)
  588  */
  589 
  590 static const char *dmi_chassis_type(u8 code)
  591 {
  592     /* 7.4.1 */
  593     static const char *type[] = {
  594         "Other", /* 0x01 */
  595         "Unknown",
  596         "Desktop",
  597         "Low Profile Desktop",
  598         "Pizza Box",
  599         "Mini Tower",
  600         "Tower",
  601         "Portable",
  602         "Laptop",
  603         "Notebook",
  604         "Hand Held",
  605         "Docking Station",
  606         "All In One",
  607         "Sub Notebook",
  608         "Space-saving",
  609         "Lunch Box",
  610         "Main Server Chassis", /* CIM_Chassis.ChassisPackageType says "Main System Chassis" */
  611         "Expansion Chassis",
  612         "Sub Chassis",
  613         "Bus Expansion Chassis",
  614         "Peripheral Chassis",
  615         "RAID Chassis",
  616         "Rack Mount Chassis",
  617         "Sealed-case PC",
  618         "Multi-system",
  619         "CompactPCI",
  620         "AdvancedTCA",
  621         "Blade",
  622         "Blade Enclosing",
  623         "Tablet",
  624         "Convertible",
  625         "Detachable",
  626         "IoT Gateway",
  627         "Embedded PC",
  628         "Mini PC",
  629         "Stick PC" /* 0x24 */
  630     };
  631 
  632     code &= 0x7F; /* bits 6:0 are chassis type, 7th bit is the lock bit */
  633 
  634     if (code >= 0x01 && code <= 0x24)
  635         return type[code - 0x01];
  636     return out_of_spec;
  637 }
  638 
  639 static const char *dmi_chassis_lock(u8 code)
  640 {
  641     static const char *lock[] = {
  642         "Not Present", /* 0x00 */
  643         "Present" /* 0x01 */
  644     };
  645 
  646     return lock[code];
  647 }
  648 
  649 static const char *dmi_chassis_state(u8 code)
  650 {
  651     /* 7.4.2 */
  652     static const char *state[] = {
  653         "Other", /* 0x01 */
  654         "Unknown",
  655         "Safe",
  656         "Warning",
  657         "Critical",
  658         "Non-recoverable" /* 0x06 */
  659     };
  660 
  661     if (code >= 0x01 && code <= 0x06)
  662         return state[code - 0x01];
  663     return out_of_spec;
  664 }
  665 
  666 static const char *dmi_chassis_security_status(u8 code)
  667 {
  668     /* 7.4.3 */
  669     static const char *status[] = {
  670         "Other", /* 0x01 */
  671         "Unknown",
  672         "None",
  673         "External Interface Locked Out",
  674         "External Interface Enabled" /* 0x05 */
  675     };
  676 
  677     if (code >= 0x01 && code <= 0x05)
  678         return status[code - 0x01];
  679     return out_of_spec;
  680 }
  681 
  682 static void dmi_chassis_height(u8 code)
  683 {
  684     if (code == 0x00)
  685         pr_attr("Height", "Unspecified");
  686     else
  687         pr_attr("Height", "%u U", code);
  688 }
  689 
  690 static void dmi_chassis_power_cords(u8 code)
  691 {
  692     if (code == 0x00)
  693         pr_attr("Number Of Power Cords", "Unspecified");
  694     else
  695         pr_attr("Number Of Power Cords", "%u", code);
  696 }
  697 
  698 static void dmi_chassis_elements(u8 count, u8 len, const u8 *p)
  699 {
  700     int i;
  701 
  702     pr_list_start("Contained Elements", "%u", count);
  703     for (i = 0; i < count; i++)
  704     {
  705         if (len >= 0x03)
  706         {
  707             const char *type;
  708 
  709             type = (p[i * len] & 0x80) ?
  710                 dmi_smbios_structure_type(p[i * len] & 0x7F) :
  711                 dmi_base_board_type(p[i * len] & 0x7F);
  712 
  713             if (p[1 + i * len] == p[2 + i * len])
  714                 pr_list_item("%s (%u)", type, p[1 + i * len]);
  715             else
  716                 pr_list_item("%s (%u-%u)", type, p[1 + i * len],
  717                          p[2 + i * len]);
  718         }
  719     }
  720     pr_list_end();
  721 }
  722 
  723 /*
  724  * 7.5 Processor Information (Type 4)
  725  */
  726 
  727 static const char *dmi_processor_type(u8 code)
  728 {
  729     /* 7.5.1 */
  730     static const char *type[] = {
  731         "Other", /* 0x01 */
  732         "Unknown",
  733         "Central Processor",
  734         "Math Processor",
  735         "DSP Processor",
  736         "Video Processor" /* 0x06 */
  737     };
  738 
  739     if (code >= 0x01 && code <= 0x06)
  740         return type[code - 0x01];
  741     return out_of_spec;
  742 }
  743 
  744 static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
  745 {
  746     const u8 *data = h->data;
  747     unsigned int i, low, high;
  748     u16 code;
  749 
  750     /* 7.5.2 */
  751     static struct {
  752         int value;
  753         const char *name;
  754     } family2[] = {
  755         { 0x01, "Other" },
  756         { 0x02, "Unknown" },
  757         { 0x03, "8086" },
  758         { 0x04, "80286" },
  759         { 0x05, "80386" },
  760         { 0x06, "80486" },
  761         { 0x07, "8087" },
  762         { 0x08, "80287" },
  763         { 0x09, "80387" },
  764         { 0x0A, "80487" },
  765         { 0x0B, "Pentium" },
  766         { 0x0C, "Pentium Pro" },
  767         { 0x0D, "Pentium II" },
  768         { 0x0E, "Pentium MMX" },
  769         { 0x0F, "Celeron" },
  770         { 0x10, "Pentium II Xeon" },
  771         { 0x11, "Pentium III" },
  772         { 0x12, "M1" },
  773         { 0x13, "M2" },
  774         { 0x14, "Celeron M" },
  775         { 0x15, "Pentium 4 HT" },
  776 
  777         { 0x18, "Duron" },
  778         { 0x19, "K5" },
  779         { 0x1A, "K6" },
  780         { 0x1B, "K6-2" },
  781         { 0x1C, "K6-3" },
  782         { 0x1D, "Athlon" },
  783         { 0x1E, "AMD29000" },
  784         { 0x1F, "K6-2+" },
  785         { 0x20, "Power PC" },
  786         { 0x21, "Power PC 601" },
  787         { 0x22, "Power PC 603" },
  788         { 0x23, "Power PC 603+" },
  789         { 0x24, "Power PC 604" },
  790         { 0x25, "Power PC 620" },
  791         { 0x26, "Power PC x704" },
  792         { 0x27, "Power PC 750" },
  793         { 0x28, "Core Duo" },
  794         { 0x29, "Core Duo Mobile" },
  795         { 0x2A, "Core Solo Mobile" },
  796         { 0x2B, "Atom" },
  797         { 0x2C, "Core M" },
  798         { 0x2D, "Core m3" },
  799         { 0x2E, "Core m5" },
  800         { 0x2F, "Core m7" },
  801         { 0x30, "Alpha" },
  802         { 0x31, "Alpha 21064" },
  803         { 0x32, "Alpha 21066" },
  804         { 0x33, "Alpha 21164" },
  805         { 0x34, "Alpha 21164PC" },
  806         { 0x35, "Alpha 21164a" },
  807         { 0x36, "Alpha 21264" },
  808         { 0x37, "Alpha 21364" },
  809         { 0x38, "Turion II Ultra Dual-Core Mobile M" },
  810         { 0x39, "Turion II Dual-Core Mobile M" },
  811         { 0x3A, "Athlon II Dual-Core M" },
  812         { 0x3B, "Opteron 6100" },
  813         { 0x3C, "Opteron 4100" },
  814         { 0x3D, "Opteron 6200" },
  815         { 0x3E, "Opteron 4200" },
  816         { 0x3F, "FX" },
  817         { 0x40, "MIPS" },
  818         { 0x41, "MIPS R4000" },
  819         { 0x42, "MIPS R4200" },
  820         { 0x43, "MIPS R4400" },
  821         { 0x44, "MIPS R4600" },
  822         { 0x45, "MIPS R10000" },
  823         { 0x46, "C-Series" },
  824         { 0x47, "E-Series" },
  825         { 0x48, "A-Series" },
  826         { 0x49, "G-Series" },
  827         { 0x4A, "Z-Series" },
  828         { 0x4B, "R-Series" },
  829         { 0x4C, "Opteron 4300" },
  830         { 0x4D, "Opteron 6300" },
  831         { 0x4E, "Opteron 3300" },
  832         { 0x4F, "FirePro" },
  833         { 0x50, "SPARC" },
  834         { 0x51, "SuperSPARC" },
  835         { 0x52, "MicroSPARC II" },
  836         { 0x53, "MicroSPARC IIep" },
  837         { 0x54, "UltraSPARC" },
  838         { 0x55, "UltraSPARC II" },
  839         { 0x56, "UltraSPARC IIi" },
  840         { 0x57, "UltraSPARC III" },
  841         { 0x58, "UltraSPARC IIIi" },
  842 
  843         { 0x60, "68040" },
  844         { 0x61, "68xxx" },
  845         { 0x62, "68000" },
  846         { 0x63, "68010" },
  847         { 0x64, "68020" },
  848         { 0x65, "68030" },
  849         { 0x66, "Athlon X4" },
  850         { 0x67, "Opteron X1000" },
  851         { 0x68, "Opteron X2000" },
  852         { 0x69, "Opteron A-Series" },
  853         { 0x6A, "Opteron X3000" },
  854         { 0x6B, "Zen" },
  855 
  856         { 0x70, "Hobbit" },
  857 
  858         { 0x78, "Crusoe TM5000" },
  859         { 0x79, "Crusoe TM3000" },
  860         { 0x7A, "Efficeon TM8000" },
  861 
  862         { 0x80, "Weitek" },
  863 
  864         { 0x82, "Itanium" },
  865         { 0x83, "Athlon 64" },
  866         { 0x84, "Opteron" },
  867         { 0x85, "Sempron" },
  868         { 0x86, "Turion 64" },
  869         { 0x87, "Dual-Core Opteron" },
  870         { 0x88, "Athlon 64 X2" },
  871         { 0x89, "Turion 64 X2" },
  872         { 0x8A, "Quad-Core Opteron" },
  873         { 0x8B, "Third-Generation Opteron" },
  874         { 0x8C, "Phenom FX" },
  875         { 0x8D, "Phenom X4" },
  876         { 0x8E, "Phenom X2" },
  877         { 0x8F, "Athlon X2" },
  878         { 0x90, "PA-RISC" },
  879         { 0x91, "PA-RISC 8500" },
  880         { 0x92, "PA-RISC 8000" },
  881         { 0x93, "PA-RISC 7300LC" },
  882         { 0x94, "PA-RISC 7200" },
  883         { 0x95, "PA-RISC 7100LC" },
  884         { 0x96, "PA-RISC 7100" },
  885 
  886         { 0xA0, "V30" },
  887         { 0xA1, "Quad-Core Xeon 3200" },
  888         { 0xA2, "Dual-Core Xeon 3000" },
  889         { 0xA3, "Quad-Core Xeon 5300" },
  890         { 0xA4, "Dual-Core Xeon 5100" },
  891         { 0xA5, "Dual-Core Xeon 5000" },
  892         { 0xA6, "Dual-Core Xeon LV" },
  893         { 0xA7, "Dual-Core Xeon ULV" },
  894         { 0xA8, "Dual-Core Xeon 7100" },
  895         { 0xA9, "Quad-Core Xeon 5400" },
  896         { 0xAA, "Quad-Core Xeon" },
  897         { 0xAB, "Dual-Core Xeon 5200" },
  898         { 0xAC, "Dual-Core Xeon 7200" },
  899         { 0xAD, "Quad-Core Xeon 7300" },
  900         { 0xAE, "Quad-Core Xeon 7400" },
  901         { 0xAF, "Multi-Core Xeon 7400" },
  902         { 0xB0, "Pentium III Xeon" },
  903         { 0xB1, "Pentium III Speedstep" },
  904         { 0xB2, "Pentium 4" },
  905         { 0xB3, "Xeon" },
  906         { 0xB4, "AS400" },
  907         { 0xB5, "Xeon MP" },
  908         { 0xB6, "Athlon XP" },
  909         { 0xB7, "Athlon MP" },
  910         { 0xB8, "Itanium 2" },
  911         { 0xB9, "Pentium M" },
  912         { 0xBA, "Celeron D" },
  913         { 0xBB, "Pentium D" },
  914         { 0xBC, "Pentium EE" },
  915         { 0xBD, "Core Solo" },
  916         /* 0xBE handled as a special case */
  917         { 0xBF, "Core 2 Duo" },
  918         { 0xC0, "Core 2 Solo" },
  919         { 0xC1, "Core 2 Extreme" },
  920         { 0xC2, "Core 2 Quad" },
  921         { 0xC3, "Core 2 Extreme Mobile" },
  922         { 0xC4, "Core 2 Duo Mobile" },
  923         { 0xC5, "Core 2 Solo Mobile" },
  924         { 0xC6, "Core i7" },
  925         { 0xC7, "Dual-Core Celeron" },
  926         { 0xC8, "IBM390" },
  927         { 0xC9, "G4" },
  928         { 0xCA, "G5" },
  929         { 0xCB, "ESA/390 G6" },
  930         { 0xCC, "z/Architecture" },
  931         { 0xCD, "Core i5" },
  932         { 0xCE, "Core i3" },
  933         { 0xCF, "Core i9" },
  934 
  935         { 0xD2, "C7-M" },
  936         { 0xD3, "C7-D" },
  937         { 0xD4, "C7" },
  938         { 0xD5, "Eden" },
  939         { 0xD6, "Multi-Core Xeon" },
  940         { 0xD7, "Dual-Core Xeon 3xxx" },
  941         { 0xD8, "Quad-Core Xeon 3xxx" },
  942         { 0xD9, "Nano" },
  943         { 0xDA, "Dual-Core Xeon 5xxx" },
  944         { 0xDB, "Quad-Core Xeon 5xxx" },
  945 
  946         { 0xDD, "Dual-Core Xeon 7xxx" },
  947         { 0xDE, "Quad-Core Xeon 7xxx" },
  948         { 0xDF, "Multi-Core Xeon 7xxx" },
  949         { 0xE0, "Multi-Core Xeon 3400" },
  950 
  951         { 0xE4, "Opteron 3000" },
  952         { 0xE5, "Sempron II" },
  953         { 0xE6, "Embedded Opteron Quad-Core" },
  954         { 0xE7, "Phenom Triple-Core" },
  955         { 0xE8, "Turion Ultra Dual-Core Mobile" },
  956         { 0xE9, "Turion Dual-Core Mobile" },
  957         { 0xEA, "Athlon Dual-Core" },
  958         { 0xEB, "Sempron SI" },
  959         { 0xEC, "Phenom II" },
  960         { 0xED, "Athlon II" },
  961         { 0xEE, "Six-Core Opteron" },
  962         { 0xEF, "Sempron M" },
  963 
  964         { 0xFA, "i860" },
  965         { 0xFB, "i960" },
  966 
  967         { 0x100, "ARMv7" },
  968         { 0x101, "ARMv8" },
  969         { 0x104, "SH-3" },
  970         { 0x105, "SH-4" },
  971         { 0x118, "ARM" },
  972         { 0x119, "StrongARM" },
  973         { 0x12C, "6x86" },
  974         { 0x12D, "MediaGX" },
  975         { 0x12E, "MII" },
  976         { 0x140, "WinChip" },
  977         { 0x15E, "DSP" },
  978         { 0x1F4, "Video Processor" },
  979 
  980         { 0x200, "RV32" },
  981         { 0x201, "RV64" },
  982         { 0x202, "RV128" },
  983     };
  984     /*
  985      * Note to developers: when adding entries to this list, check if
  986      * function dmi_processor_id below needs updating too.
  987      */
  988 
  989     /* Special case for ambiguous value 0x30 (SMBIOS 2.0 only) */
  990     if (ver == 0x0200 && data[0x06] == 0x30 && h->length >= 0x08)
  991     {
  992         const char *manufacturer = dmi_string(h, data[0x07]);
  993 
  994         if (strstr(manufacturer, "Intel") != NULL
  995          || strncasecmp(manufacturer, "Intel", 5) == 0)
  996             return "Pentium Pro";
  997     }
  998 
  999     code = (data[0x06] == 0xFE && h->length >= 0x2A) ?
 1000         WORD(data + 0x28) : data[0x06];
 1001 
 1002     /* Special case for ambiguous value 0xBE */
 1003     if (code == 0xBE)
 1004     {
 1005         if (h->length >= 0x08)
 1006         {
 1007             const char *manufacturer = dmi_string(h, data[0x07]);
 1008 
 1009             /* Best bet based on manufacturer string */
 1010             if (strstr(manufacturer, "Intel") != NULL
 1011              || strncasecmp(manufacturer, "Intel", 5) == 0)
 1012                 return "Core 2";
 1013             if (strstr(manufacturer, "AMD") != NULL
 1014              || strncasecmp(manufacturer, "AMD", 3) == 0)
 1015                 return "K7";
 1016         }
 1017 
 1018         return "Core 2 or K7";
 1019     }
 1020 
 1021     /* Perform a binary search */
 1022     low = 0;
 1023     high = ARRAY_SIZE(family2) - 1;
 1024 
 1025     while (1)
 1026     {
 1027         i = (low + high) / 2;
 1028         if (family2[i].value == code)
 1029             return family2[i].name;
 1030         if (low == high) /* Not found */
 1031             return out_of_spec;
 1032 
 1033         if (code < family2[i].value)
 1034             high = i;
 1035         else
 1036             low = i + 1;
 1037     }
 1038 }
 1039 
 1040 static void dmi_processor_id(const struct dmi_header *h)
 1041 {
 1042     /* Intel AP-485 revision 36, table 2-4 */
 1043     static const char *flags[32] = {
 1044         "FPU (Floating-point unit on-chip)", /* 0 */
 1045         "VME (Virtual mode extension)",
 1046         "DE (Debugging extension)",
 1047         "PSE (Page size extension)",
 1048         "TSC (Time stamp counter)",
 1049         "MSR (Model specific registers)",
 1050         "PAE (Physical address extension)",
 1051         "MCE (Machine check exception)",
 1052         "CX8 (CMPXCHG8 instruction supported)",
 1053         "APIC (On-chip APIC hardware supported)",
 1054         NULL, /* 10 */
 1055         "SEP (Fast system call)",
 1056         "MTRR (Memory type range registers)",
 1057         "PGE (Page global enable)",
 1058         "MCA (Machine check architecture)",
 1059         "CMOV (Conditional move instruction supported)",
 1060         "PAT (Page attribute table)",
 1061         "PSE-36 (36-bit page size extension)",
 1062         "PSN (Processor serial number present and enabled)",
 1063         "CLFSH (CLFLUSH instruction supported)",
 1064         NULL, /* 20 */
 1065         "DS (Debug store)",
 1066         "ACPI (ACPI supported)",
 1067         "MMX (MMX technology supported)",
 1068         "FXSR (FXSAVE and FXSTOR instructions supported)",
 1069         "SSE (Streaming SIMD extensions)",
 1070         "SSE2 (Streaming SIMD extensions 2)",
 1071         "SS (Self-snoop)",
 1072         "HTT (Multi-threading)",
 1073         "TM (Thermal monitor supported)",
 1074         NULL, /* 30 */
 1075         "PBE (Pending break enabled)" /* 31 */
 1076     };
 1077     const u8 *data = h->data;
 1078     const u8 *p = data + 0x08;
 1079     u32 eax, edx;
 1080     int sig = 0;
 1081     u16 type;
 1082 
 1083     type = (data[0x06] == 0xFE && h->length >= 0x2A) ?
 1084         WORD(data + 0x28) : data[0x06];
 1085 
 1086     /*
 1087      * This might help learn about new processors supporting the
 1088      * CPUID instruction or another form of identification.
 1089      */
 1090     pr_attr("ID", "%02X %02X %02X %02X %02X %02X %02X %02X",
 1091         p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
 1092 
 1093     if (type == 0x05) /* 80386 */
 1094     {
 1095         u16 dx = WORD(p);
 1096         /*
 1097          * 80386 have a different signature.
 1098          */
 1099         pr_attr("Signature",
 1100             "Type %u, Family %u, Major Stepping %u, Minor Stepping %u",
 1101             dx >> 12, (dx >> 8) & 0xF,
 1102             (dx >> 4) & 0xF, dx & 0xF);
 1103         return;
 1104     }
 1105     if (type == 0x06) /* 80486 */
 1106     {
 1107         u16 dx = WORD(p);
 1108         /*
 1109          * Not all 80486 CPU support the CPUID instruction, we have to find
 1110          * wether the one we have here does or not. Note that this trick
 1111          * works only because we know that 80486 must be little-endian.
 1112          */
 1113         if ((dx & 0x0F00) == 0x0400
 1114          && ((dx & 0x00F0) == 0x0040 || (dx & 0x00F0) >= 0x0070)
 1115          && ((dx & 0x000F) >= 0x0003))
 1116             sig = 1;
 1117         else
 1118         {
 1119             pr_attr("Signature",
 1120                 "Type %u, Family %u, Model %u, Stepping %u",
 1121                 (dx >> 12) & 0x3, (dx >> 8) & 0xF,
 1122                 (dx >> 4) & 0xF, dx & 0xF);
 1123             return;
 1124         }
 1125     }
 1126     else if ((type >= 0x100 && type <= 0x101) /* ARM */
 1127           || (type >= 0x118 && type <= 0x119)) /* ARM */
 1128     {
 1129         u32 midr = DWORD(p);
 1130         /*
 1131          * The format of this field was not defined for ARM processors
 1132          * before version 3.1.0 of the SMBIOS specification, so we
 1133          * silently skip it if it reads all zeroes.
 1134          */
 1135         if (midr == 0)
 1136             return;
 1137         pr_attr("Signature",
 1138             "Implementor 0x%02x, Variant 0x%x, Architecture %u, Part 0x%03x, Revision %u",
 1139             midr >> 24, (midr >> 20) & 0xF,
 1140             (midr >> 16) & 0xF, (midr >> 4) & 0xFFF, midr & 0xF);
 1141         return;
 1142     }
 1143     else if ((type >= 0x0B && type <= 0x15) /* Intel, Cyrix */
 1144           || (type >= 0x28 && type <= 0x2F) /* Intel */
 1145           || (type >= 0xA1 && type <= 0xB3) /* Intel */
 1146           || type == 0xB5 /* Intel */
 1147           || (type >= 0xB9 && type <= 0xC7) /* Intel */
 1148           || (type >= 0xCD && type <= 0xCF) /* Intel */
 1149           || (type >= 0xD2 && type <= 0xDB) /* VIA, Intel */
 1150           || (type >= 0xDD && type <= 0xE0)) /* Intel */
 1151         sig = 1;
 1152     else if ((type >= 0x18 && type <= 0x1D) /* AMD */
 1153           || type == 0x1F /* AMD */
 1154           || (type >= 0x38 && type <= 0x3F) /* AMD */
 1155           || (type >= 0x46 && type <= 0x4F) /* AMD */
 1156           || (type >= 0x66 && type <= 0x6B) /* AMD */
 1157           || (type >= 0x83 && type <= 0x8F) /* AMD */
 1158           || (type >= 0xB6 && type <= 0xB7) /* AMD */
 1159           || (type >= 0xE4 && type <= 0xEF)) /* AMD */
 1160         sig = 2;
 1161     else if (type == 0x01 || type == 0x02)
 1162     {
 1163         const char *version = dmi_string(h, data[0x10]);
 1164         /*
 1165          * Some X86-class CPU have family "Other" or "Unknown". In this case,
 1166          * we use the version string to determine if they are known to
 1167          * support the CPUID instruction.
 1168          */
 1169         if (strncmp(version, "Pentium III MMX", 15) == 0
 1170          || strncmp(version, "Intel(R) Core(TM)2", 18) == 0
 1171          || strncmp(version, "Intel(R) Pentium(R)", 19) == 0
 1172          || strcmp(version, "Genuine Intel(R) CPU U1400") == 0)
 1173             sig = 1;
 1174         else if (strncmp(version, "AMD Athlon(TM)", 14) == 0
 1175               || strncmp(version, "AMD Opteron(tm)", 15) == 0
 1176               || strncmp(version, "Dual-Core AMD Opteron(tm)", 25) == 0)
 1177             sig = 2;
 1178         else
 1179             return;
 1180     }
 1181     else /* neither X86 nor ARM */
 1182         return;
 1183 
 1184     /*
 1185      * Extra flags are now returned in the ECX register when one calls
 1186      * the CPUID instruction. Their meaning is explained in table 3-5, but
 1187      * DMI doesn't support this yet.
 1188      */
 1189     eax = DWORD(p);
 1190     edx = DWORD(p + 4);
 1191     switch (sig)
 1192     {
 1193         case 1: /* Intel */
 1194             pr_attr("Signature",
 1195                 "Type %u, Family %u, Model %u, Stepping %u",
 1196                 (eax >> 12) & 0x3,
 1197                 ((eax >> 20) & 0xFF) + ((eax >> 8) & 0x0F),
 1198                 ((eax >> 12) & 0xF0) + ((eax >> 4) & 0x0F),
 1199                 eax & 0xF);
 1200             break;
 1201         case 2: /* AMD, publication #25481 revision 2.28 */
 1202             pr_attr("Signature", "Family %u, Model %u, Stepping %u",
 1203                 ((eax >> 8) & 0xF) + (((eax >> 8) & 0xF) == 0xF ? (eax >> 20) & 0xFF : 0),
 1204                 ((eax >> 4) & 0xF) | (((eax >> 8) & 0xF) == 0xF ? (eax >> 12) & 0xF0 : 0),
 1205                 eax & 0xF);
 1206             break;
 1207     }
 1208 
 1209     edx = DWORD(p + 4);
 1210     if ((edx & 0xBFEFFBFF) == 0)
 1211         pr_list_start("Flags", "None");
 1212     else
 1213     {
 1214         int i;
 1215 
 1216         pr_list_start("Flags", NULL);
 1217         for (i = 0; i <= 31; i++)
 1218             if (flags[i] != NULL && edx & (1 << i))
 1219                 pr_list_item("%s", flags[i]);
 1220     }
 1221     pr_list_end();
 1222 }
 1223 
 1224 static void dmi_processor_voltage(const char *attr, u8 code)
 1225 {
 1226     /* 7.5.4 */
 1227     static const char *voltage[] = {
 1228         "5.0 V", /* 0 */
 1229         "3.3 V",
 1230         "2.9 V" /* 2 */
 1231     };
 1232     int i;
 1233 
 1234     if (code & 0x80)
 1235         pr_attr(attr, "%.1f V", (float)(code & 0x7f) / 10);
 1236     else if ((code & 0x07) == 0x00)
 1237         pr_attr(attr, "Unknown");
 1238     else
 1239     {
 1240         char voltage_str[18];
 1241         int off = 0;
 1242 
 1243         for (i = 0; i <= 2; i++)
 1244         {
 1245             if (code & (1 << i))
 1246             {
 1247                 /* Insert space if not the first value */
 1248                 off += sprintf(voltage_str + off,
 1249                            off ? " %s" :"%s",
 1250                            voltage[i]);
 1251             }
 1252         }
 1253         if (off)
 1254             pr_attr(attr, voltage_str);
 1255     }
 1256 }
 1257 
 1258 static void dmi_processor_frequency(const char *attr, const u8 *p)
 1259 {
 1260     u16 code = WORD(p);
 1261 
 1262     if (code)
 1263     {
 1264         if (attr)
 1265             pr_attr(attr, "%u MHz", code);
 1266         else
 1267             printf("%u MHz\n", code);
 1268     }
 1269     else
 1270     {
 1271         if (attr)
 1272             pr_attr(attr, "Unknown");
 1273         else
 1274             printf("Unknown\n");
 1275     }
 1276 }
 1277 
 1278 /* code is assumed to be a 3-bit value */
 1279 static const char *dmi_processor_status(u8 code)
 1280 {
 1281     static const char *status[] = {
 1282         "Unknown", /* 0x00 */
 1283         "Enabled",
 1284         "Disabled By User",
 1285         "Disabled By BIOS",
 1286         "Idle", /* 0x04 */
 1287         out_of_spec,
 1288         out_of_spec,
 1289         "Other" /* 0x07 */
 1290     };
 1291 
 1292     return status[code];
 1293 }
 1294 
 1295 static const char *dmi_processor_upgrade(u8 code)
 1296 {
 1297     /* 7.5.5 */
 1298     static const char *upgrade[] = {
 1299         "Other", /* 0x01 */
 1300         "Unknown",
 1301         "Daughter Board",
 1302         "ZIF Socket",
 1303         "Replaceable Piggy Back",
 1304         "None",
 1305         "LIF Socket",
 1306         "Slot 1",
 1307         "Slot 2",
 1308         "370-pin Socket",
 1309         "Slot A",
 1310         "Slot M",
 1311         "Socket 423",
 1312         "Socket A (Socket 462)",
 1313         "Socket 478",
 1314         "Socket 754",
 1315         "Socket 940",
 1316         "Socket 939",
 1317         "Socket mPGA604",
 1318         "Socket LGA771",
 1319         "Socket LGA775",
 1320         "Socket S1",
 1321         "Socket AM2",
 1322         "Socket F (1207)",
 1323         "Socket LGA1366",
 1324         "Socket G34",
 1325         "Socket AM3",
 1326         "Socket C32",
 1327         "Socket LGA1156",
 1328         "Socket LGA1567",
 1329         "Socket PGA988A",
 1330         "Socket BGA1288",
 1331         "Socket rPGA988B",
 1332         "Socket BGA1023",
 1333         "Socket BGA1224",
 1334         "Socket BGA1155",
 1335         "Socket LGA1356",
 1336         "Socket LGA2011",
 1337         "Socket FS1",
 1338         "Socket FS2",
 1339         "Socket FM1",
 1340         "Socket FM2",
 1341         "Socket LGA2011-3",
 1342         "Socket LGA1356-3",
 1343         "Socket LGA1150",
 1344         "Socket BGA1168",
 1345         "Socket BGA1234",
 1346         "Socket BGA1364",
 1347         "Socket AM4",
 1348         "Socket LGA1151",
 1349         "Socket BGA1356",
 1350         "Socket BGA1440",
 1351         "Socket BGA1515",
 1352         "Socket LGA3647-1",
 1353         "Socket SP3",
 1354         "Socket SP3r2",
 1355         "Socket LGA2066",
 1356         "Socket BGA1392",
 1357         "Socket BGA1510",
 1358         "Socket BGA1528" /* 0x3C */
 1359     };
 1360 
 1361     if (code >= 0x01 && code <= 0x3C)
 1362         return upgrade[code - 0x01];
 1363     return out_of_spec;
 1364 }
 1365 
 1366 static void dmi_processor_cache(const char *attr, u16 code, const char *level,
 1367                 u16 ver)
 1368 {
 1369     if (code == 0xFFFF)
 1370     {
 1371         if (ver >= 0x0203)
 1372             pr_attr(attr, "Not Provided");
 1373         else
 1374             pr_attr(attr, "No %s Cache", level);
 1375     }
 1376     else
 1377         pr_attr(attr, "0x%04X", code);
 1378 }
 1379 
 1380 static void dmi_processor_characteristics(const char *attr, u16 code)
 1381 {
 1382     /* 7.5.9 */
 1383     static const char *characteristics[] = {
 1384         "64-bit capable", /* 2 */
 1385         "Multi-Core",
 1386         "Hardware Thread",
 1387         "Execute Protection",
 1388         "Enhanced Virtualization",
 1389         "Power/Performance Control" /* 7 */
 1390     };
 1391 
 1392     if ((code & 0x00FC) == 0)
 1393         pr_attr(attr, "None");
 1394     else
 1395     {
 1396         int i;
 1397 
 1398         pr_list_start(attr, NULL);
 1399         for (i = 2; i <= 7; i++)
 1400             if (code & (1 << i))
 1401                 pr_list_item("%s", characteristics[i - 2]);
 1402         pr_list_end();
 1403     }
 1404 }
 1405 
 1406 /*
 1407  * 7.6 Memory Controller Information (Type 5)
 1408  */
 1409 
 1410 static const char *dmi_memory_controller_ed_method(u8 code)
 1411 {
 1412     /* 7.6.1 */
 1413     static const char *method[] = {
 1414         "Other", /* 0x01 */
 1415         "Unknown",
 1416         "None",
 1417         "8-bit Parity",
 1418         "32-bit ECC",
 1419         "64-bit ECC",
 1420         "128-bit ECC",
 1421         "CRC" /* 0x08 */
 1422     };
 1423 
 1424     if (code >= 0x01 && code <= 0x08)
 1425         return method[code - 0x01];
 1426     return out_of_spec;
 1427 }
 1428 
 1429 static void dmi_memory_controller_ec_capabilities(const char *attr, u8 code)
 1430 {
 1431     /* 7.6.2 */
 1432     static const char *capabilities[] = {
 1433         "Other", /* 0 */
 1434         "Unknown",
 1435         "None",
 1436         "Single-bit Error Correcting",
 1437         "Double-bit Error Correcting",
 1438         "Error Scrubbing" /* 5 */
 1439     };
 1440 
 1441     if ((code & 0x3F) == 0)
 1442         pr_attr(attr, "None");
 1443     else
 1444     {
 1445         int i;
 1446 
 1447         pr_list_start(attr, NULL);
 1448         for (i = 0; i <= 5; i++)
 1449             if (code & (1 << i))
 1450                 pr_list_item("%s", capabilities[i]);
 1451         pr_list_end();
 1452     }
 1453 }
 1454 
 1455 static const char *dmi_memory_controller_interleave(u8 code)
 1456 {
 1457     /* 7.6.3 */
 1458     static const char *interleave[] = {
 1459         "Other", /* 0x01 */
 1460         "Unknown",
 1461         "One-way Interleave",
 1462         "Two-way Interleave",
 1463         "Four-way Interleave",
 1464         "Eight-way Interleave",
 1465         "Sixteen-way Interleave" /* 0x07 */
 1466     };
 1467 
 1468     if (code >= 0x01 && code <= 0x07)
 1469         return interleave[code - 0x01];
 1470     return out_of_spec;
 1471 }
 1472 
 1473 static void dmi_memory_controller_speeds(const char *attr, u16 code)
 1474 {
 1475     /* 7.6.4 */
 1476     const char *speeds[] = {
 1477         "Other", /* 0 */
 1478         "Unknown",
 1479         "70 ns",
 1480         "60 ns",
 1481         "50 ns" /* 4 */
 1482     };
 1483 
 1484     if ((code & 0x001F) == 0)
 1485         pr_attr(attr, "None");
 1486     else
 1487     {
 1488         int i;
 1489 
 1490         pr_list_start(attr, NULL);
 1491         for (i = 0; i <= 4; i++)
 1492             if (code & (1 << i))
 1493                 pr_list_item("%s", speeds[i]);
 1494         pr_list_end();
 1495     }
 1496 }
 1497 
 1498 static void dmi_memory_controller_slots(u8 count, const u8 *p)
 1499 {
 1500     int i;
 1501 
 1502     pr_list_start("Associated Memory Slots", "%u", count);
 1503     for (i = 0; i < count; i++)
 1504         pr_list_item("0x%04X", WORD(p + sizeof(u16) * i));
 1505     pr_list_end();
 1506 }
 1507 
 1508 /*
 1509  * 7.7 Memory Module Information (Type 6)
 1510  */
 1511 
 1512 static void dmi_memory_module_types(const char *attr, u16 code, int flat)
 1513 {
 1514     /* 7.7.1 */
 1515     static const char *types[] = {
 1516         "Other", /* 0 */
 1517         "Unknown",
 1518         "Standard",
 1519         "FPM",
 1520         "EDO",
 1521         "Parity",
 1522         "ECC",
 1523         "SIMM",
 1524         "DIMM",
 1525         "Burst EDO",
 1526         "SDRAM" /* 10 */
 1527     };
 1528 
 1529     if ((code & 0x07FF) == 0)
 1530         pr_attr(attr, "None");
 1531     else if (flat)
 1532     {
 1533         char type_str[68];
 1534         int i, off = 0;
 1535 
 1536         for (i = 0; i <= 10; i++)
 1537         {
 1538             if (code & (1 << i))
 1539             {
 1540                 /* Insert space if not the first value */
 1541                 off += sprintf(type_str + off,
 1542                            off ? " %s" :"%s",
 1543                            types[i]);
 1544             }
 1545         }
 1546         if (off)
 1547             pr_attr(attr, type_str);
 1548     }
 1549     else
 1550     {
 1551         int i;
 1552 
 1553         pr_list_start(attr, NULL);
 1554         for (i = 0; i <= 10; i++)
 1555             if (code & (1 << i))
 1556                 pr_list_item("%s", types[i]);
 1557         pr_list_end();
 1558     }
 1559 }
 1560 
 1561 static void dmi_memory_module_connections(u8 code)
 1562 {
 1563     if (code == 0xFF)
 1564         pr_attr("Bank Connections", "None");
 1565     else if ((code & 0xF0) == 0xF0)
 1566         pr_attr("Bank Connections", "%u", code & 0x0F);
 1567     else if ((code & 0x0F) == 0x0F)
 1568         pr_attr("Bank Connections", "%u", code >> 4);
 1569     else
 1570         pr_attr("Bank Connections", "%u %u", code >> 4, code & 0x0F);
 1571 }
 1572 
 1573 static void dmi_memory_module_speed(const char *attr, u8 code)
 1574 {
 1575     if (code == 0)
 1576         pr_attr(attr, "Unknown");
 1577     else
 1578         pr_attr(attr, "%u ns", code);
 1579 }
 1580 
 1581 static void dmi_memory_module_size(const char *attr, u8 code)
 1582 {
 1583     const char *connection;
 1584 
 1585     /* 7.7.2 */
 1586     if (code & 0x80)
 1587         connection = " (Double-bank Connection)";
 1588     else
 1589         connection = " (Single-bank Connection)";
 1590 
 1591     switch (code & 0x7F)
 1592     {
 1593         case 0x7D:
 1594             pr_attr(attr, "Not Determinable%s", connection);
 1595             break;
 1596         case 0x7E:
 1597             pr_attr(attr, "Disabled%s", connection);
 1598             break;
 1599         case 0x7F:
 1600             pr_attr(attr, "Not Installed");
 1601             return;
 1602         default:
 1603             pr_attr(attr, "%u MB%s", 1 << (code & 0x7F),
 1604                 connection);
 1605     }
 1606 }
 1607 
 1608 static void dmi_memory_module_error(u8 code)
 1609 {
 1610     static const char *status[] = {
 1611         "OK", /* 0x00 */
 1612         "Uncorrectable Errors",
 1613         "Correctable Errors",
 1614         "Correctable and Uncorrectable Errors" /* 0x03 */
 1615     };
 1616 
 1617     if (code & (1 << 2))
 1618         pr_attr("Error Status", "See Event Log");
 1619     else
 1620         pr_attr("Error Status", "%s", status[code & 0x03]);
 1621 }
 1622 
 1623 /*
 1624  * 7.8 Cache Information (Type 7)
 1625  */
 1626 
 1627 static const char *dmi_cache_mode(u8 code)
 1628 {
 1629     static const char *mode[] = {
 1630         "Write Through", /* 0x00 */
 1631         "Write Back",
 1632         "Varies With Memory Address",
 1633         "Unknown" /* 0x03 */
 1634     };
 1635 
 1636     return mode[code];
 1637 }
 1638 
 1639 /* code is assumed to be a 2-bit value */
 1640 static const char *dmi_cache_location(u8 code)
 1641 {
 1642     static const char *location[4] = {
 1643         "Internal", /* 0x00 */
 1644         "External",
 1645         out_of_spec, /* 0x02 */
 1646         "Unknown" /* 0x03 */
 1647     };
 1648 
 1649     return location[code];
 1650 }
 1651 
 1652 static void dmi_cache_size_2(const char *attr, u32 code)
 1653 {
 1654     u64 size;
 1655 
 1656     if (code & 0x80000000)
 1657     {
 1658         code &= 0x7FFFFFFFLU;
 1659         size.l = code << 6;
 1660         size.h = code >> 26;
 1661     }
 1662     else
 1663     {
 1664         size.l = code;
 1665         size.h = 0;
 1666     }
 1667 
 1668     /* Use a more convenient unit for large cache size */
 1669     dmi_print_memory_size(attr, size, 1);
 1670 }
 1671 
 1672 static void dmi_cache_size(const char *attr, u16 code)
 1673 {
 1674     dmi_cache_size_2(attr,
 1675              (((u32)code & 0x8000LU) << 16) | (code & 0x7FFFLU));
 1676 }
 1677 
 1678 static void dmi_cache_types(const char *attr, u16 code, int flat)
 1679 {
 1680     /* 7.8.2 */
 1681     static const char *types[] = {
 1682         "Other", /* 0 */
 1683         "Unknown",
 1684         "Non-burst",
 1685         "Burst",
 1686         "Pipeline Burst",
 1687         "Synchronous",
 1688         "Asynchronous" /* 6 */
 1689     };
 1690 
 1691     if ((code & 0x007F) == 0)
 1692         pr_attr(attr, "None");
 1693     else if (flat)
 1694     {
 1695         char type_str[70];
 1696         int i, off = 0;
 1697 
 1698         for (i = 0; i <= 6; i++)
 1699         {
 1700             if (code & (1 << i))
 1701             {
 1702                 /* Insert space if not the first value */
 1703                 off += sprintf(type_str + off,
 1704                            off ? " %s" :"%s",
 1705                            types[i]);
 1706             }
 1707         }
 1708         if (off)
 1709             pr_attr(attr, type_str);
 1710     }
 1711     else
 1712     {
 1713         int i;
 1714 
 1715         pr_list_start(attr, NULL);
 1716         for (i = 0; i <= 6; i++)
 1717             if (code & (1 << i))
 1718                 pr_list_item("%s", types[i]);
 1719         pr_list_end();
 1720     }
 1721 }
 1722 
 1723 static const char *dmi_cache_ec_type(u8 code)
 1724 {
 1725     /* 7.8.3 */
 1726     static const char *type[] = {
 1727         "Other", /* 0x01 */
 1728         "Unknown",
 1729         "None",
 1730         "Parity",
 1731         "Single-bit ECC",
 1732         "Multi-bit ECC" /* 0x06 */
 1733     };
 1734 
 1735     if (code >= 0x01 && code <= 0x06)
 1736         return type[code - 0x01];
 1737     return out_of_spec;
 1738 }
 1739 
 1740 static const char *dmi_cache_type(u8 code)
 1741 {
 1742     /* 7.8.4 */
 1743     static const char *type[] = {
 1744         "Other", /* 0x01 */
 1745         "Unknown",
 1746         "Instruction",
 1747         "Data",
 1748         "Unified" /* 0x05 */
 1749     };
 1750 
 1751     if (code >= 0x01 && code <= 0x05)
 1752         return type[code - 0x01];
 1753     return out_of_spec;
 1754 }
 1755 
 1756 static const char *dmi_cache_associativity(u8 code)
 1757 {
 1758     /* 7.8.5 */
 1759     static const char *type[] = {
 1760         "Other", /* 0x01 */
 1761         "Unknown",
 1762         "Direct Mapped",
 1763         "2-way Set-associative",
 1764         "4-way Set-associative",
 1765         "Fully Associative",
 1766         "8-way Set-associative",
 1767         "16-way Set-associative",
 1768         "12-way Set-associative",
 1769         "24-way Set-associative",
 1770         "32-way Set-associative",
 1771         "48-way Set-associative",
 1772         "64-way Set-associative",
 1773         "20-way Set-associative" /* 0x0E */
 1774     };
 1775 
 1776     if (code >= 0x01 && code <= 0x0E)
 1777         return type[code - 0x01];
 1778     return out_of_spec;
 1779 }
 1780 
 1781 /*
 1782  * 7.9 Port Connector Information (Type 8)
 1783  */
 1784 
 1785 static const char *dmi_port_connector_type(u8 code)
 1786 {
 1787     /* 7.9.2 */
 1788     static const char *type[] = {
 1789         "None", /* 0x00 */
 1790         "Centronics",
 1791         "Mini Centronics",
 1792         "Proprietary",
 1793         "DB-25 male",
 1794         "DB-25 female",
 1795         "DB-15 male",
 1796         "DB-15 female",
 1797         "DB-9 male",
 1798         "DB-9 female",
 1799         "RJ-11",
 1800         "RJ-45",
 1801         "50 Pin MiniSCSI",
 1802         "Mini DIN",
 1803         "Micro DIN",
 1804         "PS/2",
 1805         "Infrared",
 1806         "HP-HIL",
 1807         "Access Bus (USB)",
 1808         "SSA SCSI",
 1809         "Circular DIN-8 male",
 1810         "Circular DIN-8 female",
 1811         "On Board IDE",
 1812         "On Board Floppy",
 1813         "9 Pin Dual Inline (pin 10 cut)",
 1814         "25 Pin Dual Inline (pin 26 cut)",
 1815         "50 Pin Dual Inline",
 1816         "68 Pin Dual Inline",
 1817         "On Board Sound Input From CD-ROM",
 1818         "Mini Centronics Type-14",
 1819         "Mini Centronics Type-26",
 1820         "Mini Jack (headphones)",
 1821         "BNC",
 1822         "IEEE 1394",
 1823         "SAS/SATA Plug Receptacle",
 1824         "USB Type-C Receptacle" /* 0x23 */
 1825     };
 1826     static const char *type_0xA0[] = {
 1827         "PC-98", /* 0xA0 */
 1828         "PC-98 Hireso",
 1829         "PC-H98",
 1830         "PC-98 Note",
 1831         "PC-98 Full" /* 0xA4 */
 1832     };
 1833 
 1834     if (code <= 0x23)
 1835         return type[code];
 1836     if (code >= 0xA0 && code <= 0xA4)
 1837         return type_0xA0[code - 0xA0];
 1838     if (code == 0xFF)
 1839         return "Other";
 1840     return out_of_spec;
 1841 }
 1842 
 1843 static const char *dmi_port_type(u8 code)
 1844 {
 1845     /* 7.9.3 */
 1846     static const char *type[] = {
 1847         "None", /* 0x00 */
 1848         "Parallel Port XT/AT Compatible",
 1849         "Parallel Port PS/2",
 1850         "Parallel Port ECP",
 1851         "Parallel Port EPP",
 1852         "Parallel Port ECP/EPP",
 1853         "Serial Port XT/AT Compatible",
 1854         "Serial Port 16450 Compatible",
 1855         "Serial Port 16550 Compatible",
 1856         "Serial Port 16550A Compatible",
 1857         "SCSI Port",
 1858         "MIDI Port",
 1859         "Joystick Port",
 1860         "Keyboard Port",
 1861         "Mouse Port",
 1862         "SSA SCSI",
 1863         "USB",
 1864         "Firewire (IEEE P1394)",
 1865         "PCMCIA Type I",
 1866         "PCMCIA Type II",
 1867         "PCMCIA Type III",
 1868         "Cardbus",
 1869         "Access Bus Port",
 1870         "SCSI II",
 1871         "SCSI Wide",
 1872         "PC-98",
 1873         "PC-98 Hireso",
 1874         "PC-H98",
 1875         "Video Port",
 1876         "Audio Port",
 1877         "Modem Port",
 1878         "Network Port",
 1879         "SATA",
 1880         "SAS" /* 0x21 */
 1881     };
 1882     static const char *type_0xA0[] = {
 1883         "8251 Compatible", /* 0xA0 */
 1884         "8251 FIFO Compatible" /* 0xA1 */
 1885     };
 1886 
 1887     if (code <= 0x21)
 1888         return type[code];
 1889     if (code >= 0xA0 && code <= 0xA1)
 1890         return type_0xA0[code - 0xA0];
 1891     if (code == 0xFF)
 1892         return "Other";
 1893     return out_of_spec;
 1894 }
 1895 
 1896 /*
 1897  * 7.10 System Slots (Type 9)
 1898  */
 1899 
 1900 static const char *dmi_slot_type(u8 code)
 1901 {
 1902     /* 7.10.1 */
 1903     static const char *type[] = {
 1904         "Other", /* 0x01 */
 1905         "Unknown",
 1906         "ISA",
 1907         "MCA",
 1908         "EISA",
 1909         "PCI",
 1910         "PC Card (PCMCIA)",
 1911         "VLB",
 1912         "Proprietary",
 1913         "Processor Card",
 1914         "Proprietary Memory Card",
 1915         "I/O Riser Card",
 1916         "NuBus",
 1917         "PCI-66",
 1918         "AGP",
 1919         "AGP 2x",
 1920         "AGP 4x",
 1921         "PCI-X",
 1922         "AGP 8x",
 1923         "M.2 Socket 1-DP",
 1924         "M.2 Socket 1-SD",
 1925         "M.2 Socket 2",
 1926         "M.2 Socket 3",
 1927         "MXM Type I",
 1928         "MXM Type II",
 1929         "MXM Type III",
 1930         "MXM Type III-HE",
 1931         "MXM Type IV",
 1932         "MXM 3.0 Type A",
 1933         "MXM 3.0 Type B",
 1934         "PCI Express 2 SFF-8639",
 1935         "PCI Express 3 SFF-8639",
 1936         "PCI Express Mini 52-pin with bottom-side keep-outs",
 1937         "PCI Express Mini 52-pin without bottom-side keep-outs",
 1938         "PCI Express Mini 76-pin" /* 0x23 */
 1939     };
 1940     static const char *type_0x30[] = {
 1941         "CXL FLexbus 1.0" /* 0x30 */
 1942     };
 1943     static const char *type_0xA0[] = {
 1944         "PC-98/C20", /* 0xA0 */
 1945         "PC-98/C24",
 1946         "PC-98/E",
 1947         "PC-98/Local Bus",
 1948         "PC-98/Card",
 1949         "PCI Express",
 1950         "PCI Express x1",
 1951         "PCI Express x2",
 1952         "PCI Express x4",
 1953         "PCI Express x8",
 1954         "PCI Express x16",
 1955         "PCI Express 2",
 1956         "PCI Express 2 x1",
 1957         "PCI Express 2 x2",
 1958         "PCI Express 2 x4",
 1959         "PCI Express 2 x8",
 1960         "PCI Express 2 x16",
 1961         "PCI Express 3",
 1962         "PCI Express 3 x1",
 1963         "PCI Express 3 x2",
 1964         "PCI Express 3 x4",
 1965         "PCI Express 3 x8",
 1966         "PCI Express 3 x16",
 1967         out_of_spec, /* 0xB7 */
 1968         "PCI Express 4",
 1969         "PCI Express 4 x1",
 1970         "PCI Express 4 x2",
 1971         "PCI Express 4 x4",
 1972         "PCI Express 4 x8",
 1973         "PCI Express 4 x16" /* 0xBD */
 1974     };
 1975     /*
 1976      * Note to developers: when adding entries to these lists, check if
 1977      * function dmi_slot_id below needs updating too.
 1978      */
 1979 
 1980     if (code >= 0x01 && code <= 0x23)
 1981         return type[code - 0x01];
 1982     if (code == 0x30)
 1983         return type_0x30[code - 0x30];
 1984     if (code >= 0xA0 && code <= 0xBD)
 1985         return type_0xA0[code - 0xA0];
 1986     return out_of_spec;
 1987 }
 1988 
 1989 static const char *dmi_slot_bus_width(u8 code)
 1990 {
 1991     /* 7.10.2 */
 1992     static const char *width[] = {
 1993         "", /* 0x01, "Other" */
 1994         "", /* "Unknown" */
 1995         "8-bit ",
 1996         "16-bit ",
 1997         "32-bit ",
 1998         "64-bit ",
 1999         "128-bit ",
 2000         "x1 ",
 2001         "x2 ",
 2002         "x4 ",
 2003         "x8 ",
 2004         "x12 ",
 2005         "x16 ",
 2006         "x32 " /* 0x0E */
 2007     };
 2008 
 2009     if (code >= 0x01 && code <= 0x0E)
 2010         return width[code - 0x01];
 2011     return out_of_spec;
 2012 }
 2013 
 2014 static const char *dmi_slot_current_usage(u8 code)
 2015 {
 2016     /* 7.10.3 */
 2017     static const char *usage[] = {
 2018         "Other", /* 0x01 */
 2019         "Unknown",
 2020         "Available",
 2021         "In Use",
 2022         "Unavailable" /* 0x05 */
 2023     };
 2024 
 2025     if (code >= 0x01 && code <= 0x05)
 2026         return usage[code - 0x01];
 2027     return out_of_spec;
 2028 }
 2029 
 2030 static const char *dmi_slot_length(u8 code)
 2031 {
 2032     /* 7.10.4 */
 2033     static const char *length[] = {
 2034         "Other", /* 0x01 */
 2035         "Unknown",
 2036         "Short",
 2037         "Long",
 2038         "2.5\" drive form factor",
 2039         "3.5\" drive form factor" /* 0x06 */
 2040     };
 2041 
 2042     if (code >= 0x01 && code <= 0x06)
 2043         return length[code - 0x01];
 2044     return out_of_spec;
 2045 }
 2046 
 2047 static void dmi_slot_id(u8 code1, u8 code2, u8 type)
 2048 {
 2049     /* 7.10.5 */
 2050     switch (type)
 2051     {
 2052         case 0x04: /* MCA */
 2053             pr_attr("ID", "%u", code1);
 2054             break;
 2055         case 0x05: /* EISA */
 2056             pr_attr("ID", "%u", code1);
 2057             break;
 2058         case 0x06: /* PCI */
 2059         case 0x0E: /* PCI */
 2060         case 0x0F: /* AGP */
 2061         case 0x10: /* AGP */
 2062         case 0x11: /* AGP */
 2063         case 0x12: /* PCI-X */
 2064         case 0x13: /* AGP */
 2065         case 0x1F: /* PCI Express 2 */
 2066         case 0x20: /* PCI Express 3 */
 2067         case 0x21: /* PCI Express Mini */
 2068         case 0x22: /* PCI Express Mini */
 2069         case 0x23: /* PCI Express Mini */
 2070         case 0xA5: /* PCI Express */
 2071         case 0xA6: /* PCI Express */
 2072         case 0xA7: /* PCI Express */
 2073         case 0xA8: /* PCI Express */
 2074         case 0xA9: /* PCI Express */
 2075         case 0xAA: /* PCI Express */
 2076         case 0xAB: /* PCI Express 2 */
 2077         case 0xAC: /* PCI Express 2 */
 2078         case 0xAD: /* PCI Express 2 */
 2079         case 0xAE: /* PCI Express 2 */
 2080         case 0xAF: /* PCI Express 2 */
 2081         case 0xB0: /* PCI Express 2 */
 2082         case 0xB1: /* PCI Express 3 */
 2083         case 0xB2: /* PCI Express 3 */
 2084         case 0xB3: /* PCI Express 3 */
 2085         case 0xB4: /* PCI Express 3 */
 2086         case 0xB5: /* PCI Express 3 */
 2087         case 0xB6: /* PCI Express 3 */
 2088         case 0xB8: /* PCI Express 4 */
 2089         case 0xB9: /* PCI Express 4 */
 2090         case 0xBA: /* PCI Express 4 */
 2091         case 0xBB: /* PCI Express 4 */
 2092         case 0xBC: /* PCI Express 4 */
 2093         case 0xBD: /* PCI Express 4 */
 2094             pr_attr("ID", "%u", code1);
 2095             break;
 2096         case 0x07: /* PCMCIA */
 2097             pr_attr("ID", "Adapter %u, Socket %u", code1, code2);
 2098             break;
 2099     }
 2100 }
 2101 
 2102 static void dmi_slot_characteristics(const char *attr, u8 code1, u8 code2)
 2103 {
 2104     /* 7.10.6 */
 2105     static const char *characteristics1[] = {
 2106         "5.0 V is provided", /* 1 */
 2107         "3.3 V is provided",
 2108         "Opening is shared",
 2109         "PC Card-16 is supported",
 2110         "Cardbus is supported",
 2111         "Zoom Video is supported",
 2112         "Modem ring resume is supported" /* 7 */
 2113     };
 2114     /* 7.10.7 */
 2115     static const char *characteristics2[] = {
 2116         "PME signal is supported", /* 0 */
 2117         "Hot-plug devices are supported",
 2118         "SMBus signal is supported",
 2119         "PCIe slot bifurcation is supported" /* 3 */
 2120     };
 2121 
 2122     if (code1 & (1 << 0))
 2123         pr_attr(attr, "Unknown");
 2124     else if ((code1 & 0xFE) == 0 && (code2 & 0x07) == 0)
 2125         pr_attr(attr, "None");
 2126     else
 2127     {
 2128         int i;
 2129 
 2130         pr_list_start(attr, NULL);
 2131         for (i = 1; i <= 7; i++)
 2132             if (code1 & (1 << i))
 2133                 pr_list_item("%s", characteristics1[i - 1]);
 2134         for (i = 0; i <= 3; i++)
 2135             if (code2 & (1 << i))
 2136                 pr_list_item("%s", characteristics2[i]);
 2137         pr_list_end();
 2138     }
 2139 }
 2140 
 2141 static void dmi_slot_segment_bus_func(u16 code1, u8 code2, u8 code3)
 2142 {
 2143     /* 7.10.8 */
 2144     if (!(code1 == 0xFFFF && code2 == 0xFF && code3 == 0xFF))
 2145         pr_attr("Bus Address", "%04x:%02x:%02x.%x",
 2146             code1, code2, code3 >> 3, code3 & 0x7);
 2147 }
 2148 
 2149 static void dmi_slot_peers(u8 n, const u8 *data)
 2150 {
 2151     char attr[16];
 2152     int i;
 2153 
 2154     for (i = 1; i <= n; i++, data += 5)
 2155     {
 2156         sprintf(attr, "Peer Device %hu", i);
 2157         pr_attr(attr, "%04x:%02x:%02x.%x (Width %u)",
 2158             WORD(data), data[2], data[3] >> 3, data[3] & 0x07,
 2159             data[4]);
 2160     }
 2161 }
 2162 
 2163 /*
 2164  * 7.11 On Board Devices Information (Type 10)
 2165  */
 2166 
 2167 static const char *dmi_on_board_devices_type(u8 code)
 2168 {
 2169     /* 7.11.1 and 7.42.2 */
 2170     static const char *type[] = {
 2171         "Other", /* 0x01 */
 2172         "Unknown",
 2173         "Video",
 2174         "SCSI Controller",
 2175         "Ethernet",
 2176         "Token Ring",
 2177         "Sound",
 2178         "PATA Controller",
 2179         "SATA Controller",
 2180         "SAS Controller" /* 0x0A */
 2181     };
 2182 
 2183     if (code >= 0x01 && code <= 0x0A)
 2184         return type[code - 0x01];
 2185     return out_of_spec;
 2186 }
 2187 
 2188 static void dmi_on_board_devices(const struct dmi_header *h)
 2189 {
 2190     u8 *p = h->data + 4;
 2191     u8 count = (h->length - 0x04) / 2;
 2192     int i;
 2193 
 2194     for (i = 0; i < count; i++)
 2195     {
 2196         if (count == 1)
 2197             pr_handle_name("On Board Device Information");
 2198         else
 2199             pr_handle_name("On Board Device %d Information",
 2200                        i + 1);
 2201         pr_attr("Type", "%s",
 2202             dmi_on_board_devices_type(p[2 * i] & 0x7F));
 2203         pr_attr("Status", "%s",
 2204             p[2 * i] & 0x80 ? "Enabled" : "Disabled");
 2205         pr_attr("Description", "%s", dmi_string(h, p[2 * i + 1]));
 2206     }
 2207 }
 2208 
 2209 /*
 2210  * 7.12 OEM Strings (Type 11)
 2211  */
 2212 
 2213 static void dmi_oem_strings(const struct dmi_header *h)
 2214 {
 2215     char attr[11];
 2216     u8 *p = h->data + 4;
 2217     u8 count = p[0x00];
 2218     int i;
 2219 
 2220     for (i = 1; i <= count; i++)
 2221     {
 2222         sprintf(attr, "String %hu", i);
 2223         pr_attr(attr, "%s",dmi_string(h, i));
 2224     }
 2225 }
 2226 
 2227 /*
 2228  * 7.13 System Configuration Options (Type 12)
 2229  */
 2230 
 2231 static void dmi_system_configuration_options(const struct dmi_header *h)
 2232 {
 2233     char attr[11];
 2234     u8 *p = h->data + 4;
 2235     u8 count = p[0x00];
 2236     int i;
 2237 
 2238     for (i = 1; i <= count; i++)
 2239     {
 2240         sprintf(attr, "Option %hu", i);
 2241         pr_attr(attr, "%s",dmi_string(h, i));
 2242     }
 2243 }
 2244 
 2245 /*
 2246  * 7.14 BIOS Language Information (Type 13)
 2247  */
 2248 
 2249 static void dmi_bios_languages(const struct dmi_header *h)
 2250 {
 2251     u8 *p = h->data + 4;
 2252     u8 count = p[0x00];
 2253     int i;
 2254 
 2255     for (i = 1; i <= count; i++)
 2256         pr_list_item("%s", dmi_string(h, i));
 2257 }
 2258 
 2259 static const char *dmi_bios_language_format(u8 code)
 2260 {
 2261     if (code & 0x01)
 2262         return "Abbreviated";
 2263     else
 2264         return "Long";
 2265 }
 2266 
 2267 /*
 2268  * 7.15 Group Associations (Type 14)
 2269  */
 2270 
 2271 static void dmi_group_associations_items(u8 count, const u8 *p)
 2272 {
 2273     int i;
 2274 
 2275     for (i = 0; i < count; i++)
 2276     {
 2277         pr_list_item("0x%04X (%s)",
 2278             WORD(p + 3 * i + 1),
 2279             dmi_smbios_structure_type(p[3 * i]));
 2280     }
 2281 }
 2282 
 2283 /*
 2284  * 7.16 System Event Log (Type 15)
 2285  */
 2286 
 2287 static const char *dmi_event_log_method(u8 code)
 2288 {
 2289     static const char *method[] = {
 2290         "Indexed I/O, one 8-bit index port, one 8-bit data port", /* 0x00 */
 2291         "Indexed I/O, two 8-bit index ports, one 8-bit data port",
 2292         "Indexed I/O, one 16-bit index port, one 8-bit data port",
 2293         "Memory-mapped physical 32-bit address",
 2294         "General-purpose non-volatile data functions" /* 0x04 */
 2295     };
 2296 
 2297     if (code <= 0x04)
 2298         return method[code];
 2299     if (code >= 0x80)
 2300         return "OEM-specific";
 2301     return out_of_spec;
 2302 }
 2303 
 2304 static void dmi_event_log_status(u8 code)
 2305 {
 2306     static const char *valid[] = {
 2307         "Invalid", /* 0 */
 2308         "Valid" /* 1 */
 2309     };
 2310     static const char *full[] = {
 2311         "Not Full", /* 0 */
 2312         "Full" /* 1 */
 2313     };
 2314 
 2315     pr_attr("Status", "%s, %s",
 2316         valid[(code >> 0) & 1], full[(code >> 1) & 1]);
 2317 }
 2318 
 2319 static void dmi_event_log_address(u8 method, const u8 *p)
 2320 {
 2321     /* 7.16.3 */
 2322     switch (method)
 2323     {
 2324         case 0x00:
 2325         case 0x01:
 2326         case 0x02:
 2327             pr_attr("Access Address", "Index 0x%04X, Data 0x%04X",
 2328                 WORD(p), WORD(p + 2));
 2329             break;
 2330         case 0x03:
 2331             pr_attr("Access Address", "0x%08X", DWORD(p));
 2332             break;
 2333         case 0x04:
 2334             pr_attr("Access Address", "0x%04X", WORD(p));
 2335             break;
 2336         default:
 2337             pr_attr("Access Address", "Unknown");
 2338     }
 2339 }
 2340 
 2341 static const char *dmi_event_log_header_type(u8 code)
 2342 {
 2343     static const char *type[] = {
 2344         "No Header", /* 0x00 */
 2345         "Type 1" /* 0x01 */
 2346     };
 2347 
 2348     if (code <= 0x01)
 2349         return type[code];
 2350     if (code >= 0x80)
 2351         return "OEM-specific";
 2352     return out_of_spec;
 2353 }
 2354 
 2355 static const char *dmi_event_log_descriptor_type(u8 code)
 2356 {
 2357     /* 7.16.6.1 */
 2358     static const char *type[] = {
 2359         NULL, /* 0x00 */
 2360         "Single-bit ECC memory error",
 2361         "Multi-bit ECC memory error",
 2362         "Parity memory error",
 2363         "Bus timeout",
 2364         "I/O channel block",
 2365         "Software NMI",
 2366         "POST memory resize",
 2367         "POST error",
 2368         "PCI parity error",
 2369         "PCI system error",
 2370         "CPU failure",
 2371         "EISA failsafe timer timeout",
 2372         "Correctable memory log disabled",
 2373         "Logging disabled",
 2374         NULL, /* 0x0F */
 2375         "System limit exceeded",
 2376         "Asynchronous hardware timer expired",
 2377         "System configuration information",
 2378         "Hard disk information",
 2379         "System reconfigured",
 2380         "Uncorrectable CPU-complex error",
 2381         "Log area reset/cleared",
 2382         "System boot" /* 0x17 */
 2383     };
 2384 
 2385     if (code <= 0x17 && type[code] != NULL)
 2386         return type[code];
 2387     if (code >= 0x80 && code <= 0xFE)
 2388         return "OEM-specific";
 2389     if (code == 0xFF)
 2390         return "End of log";
 2391     return out_of_spec;
 2392 }
 2393 
 2394 static const char *dmi_event_log_descriptor_format(u8 code)
 2395 {
 2396     /* 7.16.6.2 */
 2397     static const char *format[] = {
 2398         "None", /* 0x00 */
 2399         "Handle",
 2400         "Multiple-event",
 2401         "Multiple-event handle",
 2402         "POST results bitmap",
 2403         "System management",
 2404         "Multiple-event system management" /* 0x06 */
 2405     };
 2406 
 2407     if (code <= 0x06)
 2408         return format[code];
 2409     if (code >= 0x80)
 2410         return "OEM-specific";
 2411     return out_of_spec;
 2412 }
 2413 
 2414 static void dmi_event_log_descriptors(u8 count, u8 len, const u8 *p)
 2415 {
 2416     /* 7.16.1 */
 2417     char attr[16];
 2418     int i;
 2419 
 2420     for (i = 0; i < count; i++)
 2421     {
 2422         if (len >= 0x02)
 2423         {
 2424             sprintf(attr, "Descriptor %hu", i + 1);
 2425             pr_attr(attr, "%s",
 2426                 dmi_event_log_descriptor_type(p[i * len]));
 2427             sprintf(attr, "Data Format %hu", i + 1);
 2428             pr_attr(attr, "%s",
 2429                 dmi_event_log_descriptor_format(p[i * len + 1]));
 2430         }
 2431     }
 2432 }
 2433 
 2434 /*
 2435  * 7.17 Physical Memory Array (Type 16)
 2436  */
 2437 
 2438 static const char *dmi_memory_array_location(u8 code)
 2439 {
 2440     /* 7.17.1 */
 2441     static const char *location[] = {
 2442         "Other", /* 0x01 */
 2443         "Unknown",
 2444         "System Board Or Motherboard",
 2445         "ISA Add-on Card",
 2446         "EISA Add-on Card",
 2447         "PCI Add-on Card",
 2448         "MCA Add-on Card",
 2449         "PCMCIA Add-on Card",
 2450         "Proprietary Add-on Card",
 2451         "NuBus" /* 0x0A */
 2452     };
 2453     static const char *location_0xA0[] = {
 2454         "PC-98/C20 Add-on Card", /* 0xA0 */
 2455         "PC-98/C24 Add-on Card",
 2456         "PC-98/E Add-on Card",
 2457         "PC-98/Local Bus Add-on Card",
 2458         "CXL Flexbus 1.0" /* 0xA4 */
 2459     };
 2460 
 2461     if (code >= 0x01 && code <= 0x0A)
 2462         return location[code - 0x01];
 2463     if (code >= 0xA0 && code <= 0xA4)
 2464         return location_0xA0[code - 0xA0];
 2465     return out_of_spec;
 2466 }
 2467 
 2468 static const char *dmi_memory_array_use(u8 code)
 2469 {
 2470     /* 7.17.2 */
 2471     static const char *use[] = {
 2472         "Other", /* 0x01 */
 2473         "Unknown",
 2474         "System Memory",
 2475         "Video Memory",
 2476         "Flash Memory",
 2477         "Non-volatile RAM",
 2478         "Cache Memory" /* 0x07 */
 2479     };
 2480 
 2481     if (code >= 0x01 && code <= 0x07)
 2482         return use[code - 0x01];
 2483     return out_of_spec;
 2484 }
 2485 
 2486 static const char *dmi_memory_array_ec_type(u8 code)
 2487 {
 2488     /* 7.17.3 */
 2489     static const char *type[] = {
 2490         "Other", /* 0x01 */
 2491         "Unknown",
 2492         "None",
 2493         "Parity",
 2494         "Single-bit ECC",
 2495         "Multi-bit ECC",
 2496         "CRC" /* 0x07 */
 2497     };
 2498 
 2499     if (code >= 0x01 && code <= 0x07)
 2500         return type[code - 0x01];
 2501     return out_of_spec;
 2502 }
 2503 
 2504 static void dmi_memory_array_error_handle(u16 code)
 2505 {
 2506     if (code == 0xFFFE)
 2507         pr_attr("Error Information Handle", "Not Provided");
 2508     else if (code == 0xFFFF)
 2509         pr_attr("Error Information Handle", "No Error");
 2510     else
 2511         pr_attr("Error Information Handle", "0x%04X", code);
 2512 }
 2513 
 2514 /*
 2515  * 7.18 Memory Device (Type 17)
 2516  */
 2517 
 2518 static void dmi_memory_device_width(const char *attr, u16 code)
 2519 {
 2520     /*
 2521      * If no memory module is present, width may be 0
 2522      */
 2523     if (code == 0xFFFF || code == 0)
 2524         pr_attr(attr, "Unknown");
 2525     else
 2526         pr_attr(attr, "%u bits", code);
 2527 }
 2528 
 2529 static void dmi_memory_device_size(u16 code)
 2530 {
 2531     if (code == 0)
 2532         pr_attr("Size", "No Module Installed");
 2533     else if (code == 0xFFFF)
 2534         pr_attr("Size", "Unknown");
 2535     else
 2536     {
 2537         u64 s = { .l = code & 0x7FFF };
 2538         if (!(code & 0x8000))
 2539             s.l <<= 10;
 2540         dmi_print_memory_size("Size", s, 1);
 2541     }
 2542 }
 2543 
 2544 static void dmi_memory_device_extended_size(u32 code)
 2545 {
 2546     code &= 0x7FFFFFFFUL;
 2547 
 2548     /*
 2549      * Use the greatest unit for which the exact value can be displayed
 2550      * as an integer without rounding
 2551      */
 2552     if (code & 0x3FFUL)
 2553         pr_attr("Size", "%lu MB", (unsigned long)code);
 2554     else if (code & 0xFFC00UL)
 2555         pr_attr("Size", "%lu GB", (unsigned long)code >> 10);
 2556     else
 2557         pr_attr("Size", "%lu TB", (unsigned long)code >> 20);
 2558 }
 2559 
 2560 static void dmi_memory_voltage_value(const char *attr, u16 code)
 2561 {
 2562     if (code == 0)
 2563         pr_attr(attr, "Unknown");
 2564     else
 2565         pr_attr(attr, code % 100 ? "%g V" : "%.1f V",
 2566             (float)code / 1000);
 2567 }
 2568 
 2569 static const char *dmi_memory_device_form_factor(u8 code)
 2570 {
 2571     /* 7.18.1 */
 2572     static const char *form_factor[] = {
 2573         "Other", /* 0x01 */
 2574         "Unknown",
 2575         "SIMM",
 2576         "SIP",
 2577         "Chip",
 2578         "DIP",
 2579         "ZIP",
 2580         "Proprietary Card",
 2581         "DIMM",
 2582         "TSOP",
 2583         "Row Of Chips",
 2584         "RIMM",
 2585         "SODIMM",
 2586         "SRIMM",
 2587         "FB-DIMM",
 2588         "Die" /* 0x10 */
 2589     };
 2590 
 2591     if (code >= 0x01 && code <= 0x10)
 2592         return form_factor[code - 0x01];
 2593     return out_of_spec;
 2594 }
 2595 
 2596 static void dmi_memory_device_set(u8 code)
 2597 {
 2598     if (code == 0)
 2599         pr_attr("Set", "None");
 2600     else if (code == 0xFF)
 2601         pr_attr("Set", "Unknown");
 2602     else
 2603         pr_attr("Set", "%u", code);
 2604 }
 2605 
 2606 static const char *dmi_memory_device_type(u8 code)
 2607 {
 2608     /* 7.18.2 */
 2609     static const char *type[] = {
 2610         "Other", /* 0x01 */
 2611         "Unknown",
 2612         "DRAM",
 2613         "EDRAM",
 2614         "VRAM",
 2615         "SRAM",
 2616         "RAM",
 2617         "ROM",
 2618         "Flash",
 2619         "EEPROM",
 2620         "FEPROM",
 2621         "EPROM",
 2622         "CDRAM",
 2623         "3DRAM",
 2624         "SDRAM",
 2625         "SGRAM",
 2626         "RDRAM",
 2627         "DDR",
 2628         "DDR2",
 2629         "DDR2 FB-DIMM",
 2630         "Reserved",
 2631         "Reserved",
 2632         "Reserved",
 2633         "DDR3",
 2634         "FBD2",
 2635         "DDR4",
 2636         "LPDDR",
 2637         "LPDDR2",
 2638         "LPDDR3",
 2639         "LPDDR4",
 2640         "Logical non-volatile device",
 2641         "HBM",
 2642         "HBM2" /* 0x21 */
 2643     };
 2644 
 2645     if (code >= 0x01 && code <= 0x21)
 2646         return type[code - 0x01];
 2647     return out_of_spec;
 2648 }
 2649 
 2650 static void dmi_memory_device_type_detail(u16 code)
 2651 {
 2652     /* 7.18.3 */
 2653     static const char *detail[] = {
 2654         "Other", /* 1 */
 2655         "Unknown",
 2656         "Fast-paged",
 2657         "Static Column",
 2658         "Pseudo-static",
 2659         "RAMBus",
 2660         "Synchronous",
 2661         "CMOS",
 2662         "EDO",
 2663         "Window DRAM",
 2664         "Cache DRAM",
 2665         "Non-Volatile",
 2666         "Registered (Buffered)",
 2667         "Unbuffered (Unregistered)",
 2668         "LRDIMM"  /* 15 */
 2669     };
 2670     char list[172];     /* Update length if you touch the array above */
 2671 
 2672     if ((code & 0xFFFE) == 0)
 2673         pr_attr("Type Detail", "None");
 2674     else
 2675     {
 2676         int i, off = 0;
 2677 
 2678         list[0] = '\0';
 2679         for (i = 1; i <= 15; i++)
 2680             if (code & (1 << i))
 2681                 off += sprintf(list + off, off ? " %s" : "%s",
 2682                            detail[i - 1]);
 2683         pr_attr("Type Detail", list);
 2684     }
 2685 }
 2686 
 2687 static void dmi_memory_device_speed(const char *attr, u16 code)
 2688 {
 2689     if (code == 0)
 2690         pr_attr(attr, "Unknown");
 2691     else
 2692         pr_attr(attr, "%u MT/s", code);
 2693 }
 2694 
 2695 static void dmi_memory_technology(u8 code)
 2696 {
 2697     /* 7.18.6 */
 2698     static const char * const technology[] = {
 2699         "Other", /* 0x01 */
 2700         "Unknown",
 2701         "DRAM",
 2702         "NVDIMM-N",
 2703         "NVDIMM-F",
 2704         "NVDIMM-P",
 2705         "Intel Optane DC persistent memory" /* 0x07 */
 2706     };
 2707     if (code >= 0x01 && code <= 0x07)
 2708         pr_attr("Memory Technology", "%s", technology[code - 0x01]);
 2709     else
 2710         pr_attr("Memory Technology", "%s", out_of_spec);
 2711 }
 2712 
 2713 static void dmi_memory_operating_mode_capability(u16 code)
 2714 {
 2715     /* 7.18.7 */
 2716     static const char * const mode[] = {
 2717         "Other", /* 1 */
 2718         "Unknown",
 2719         "Volatile memory",
 2720         "Byte-accessible persistent memory",
 2721         "Block-accessible persistent memory" /* 5 */
 2722     };
 2723     char list[99];      /* Update length if you touch the array above */
 2724 
 2725     if ((code & 0xFFFE) == 0)
 2726         pr_attr("Memory Operating Mode Capability", "None");
 2727     else {
 2728         int i, off = 0;
 2729 
 2730         list[0] = '\0';
 2731         for (i = 1; i <= 5; i++)
 2732             if (code & (1 << i))
 2733                 off += sprintf(list + off, off ? " %s" : "%s",
 2734                            mode[i - 1]);
 2735         pr_attr("Memory Operating Mode Capability", list);
 2736     }
 2737 }
 2738 
 2739 static void dmi_memory_manufacturer_id(const char *attr, u16 code)
 2740 {
 2741     /* 7.18.8 */
 2742     /* 7.18.10 */
 2743     /* LSB is 7-bit Odd Parity number of continuation codes */
 2744     if (code == 0)
 2745         pr_attr(attr, "Unknown");
 2746     else
 2747         pr_attr(attr, "Bank %d, Hex 0x%02X",
 2748             (code & 0x7F) + 1, code >> 8);
 2749 }
 2750 
 2751 static void dmi_memory_product_id(const char *attr, u16 code)
 2752 {
 2753     /* 7.18.9 */
 2754     /* 7.18.11 */
 2755     if (code == 0)
 2756         pr_attr(attr, "Unknown");
 2757     else
 2758         pr_attr(attr, "0x%04X", code);
 2759 }
 2760 
 2761 static void dmi_memory_size(const char *attr, u64 code)
 2762 {
 2763     /* 7.18.12 */
 2764     /* 7.18.13 */
 2765     if (code.h == 0xFFFFFFFF && code.l == 0xFFFFFFFF)
 2766         pr_attr(attr, "Unknown");
 2767     else if (code.h == 0x0 && code.l == 0x0)
 2768         pr_attr(attr, "None");
 2769     else
 2770         dmi_print_memory_size(attr, code, 0);
 2771 }
 2772 
 2773 /*
 2774  * 7.19 32-bit Memory Error Information (Type 18)
 2775  */
 2776 
 2777 static const char *dmi_memory_error_type(u8 code)
 2778 {
 2779     /* 7.19.1 */
 2780     static const char *type[] = {
 2781         "Other", /* 0x01 */
 2782         "Unknown",
 2783         "OK",
 2784         "Bad Read",
 2785         "Parity Error",
 2786         "Single-bit Error",
 2787         "Double-bit Error",
 2788         "Multi-bit Error",
 2789         "Nibble Error",
 2790         "Checksum Error",
 2791         "CRC Error",
 2792         "Corrected Single-bit Error",
 2793         "Corrected Error",
 2794         "Uncorrectable Error" /* 0x0E */
 2795     };
 2796 
 2797     if (code >= 0x01 && code <= 0x0E)
 2798         return type[code - 0x01];
 2799     return out_of_spec;
 2800 }
 2801 
 2802 static const char *dmi_memory_error_granularity(u8 code)
 2803 {
 2804     /* 7.19.2 */
 2805     static const char *granularity[] = {
 2806         "Other", /* 0x01 */
 2807         "Unknown",
 2808         "Device Level",
 2809         "Memory Partition Level" /* 0x04 */
 2810     };
 2811 
 2812     if (code >= 0x01 && code <= 0x04)
 2813         return granularity[code - 0x01];
 2814     return out_of_spec;
 2815 }
 2816 
 2817 static const char *dmi_memory_error_operation(u8 code)
 2818 {
 2819     /* 7.19.3 */
 2820     static const char *operation[] = {
 2821         "Other", /* 0x01 */
 2822         "Unknown",
 2823         "Read",
 2824         "Write",
 2825         "Partial Write" /* 0x05 */
 2826     };
 2827 
 2828     if (code >= 0x01 && code <= 0x05)
 2829         return operation[code - 0x01];
 2830     return out_of_spec;
 2831 }
 2832 
 2833 static void dmi_memory_error_syndrome(u32 code)
 2834 {
 2835     if (code == 0x00000000)
 2836         pr_attr("Vendor Syndrome", "Unknown");
 2837     else
 2838         pr_attr("Vendor Syndrome", "0x%08X", code);
 2839 }
 2840 
 2841 static void dmi_32bit_memory_error_address(const char *attr, u32 code)
 2842 {
 2843     if (code == 0x80000000)
 2844         pr_attr(attr, "Unknown");
 2845     else
 2846         pr_attr(attr, "0x%08X", code);
 2847 }
 2848 
 2849 /*
 2850  * 7.20 Memory Array Mapped Address (Type 19)
 2851  */
 2852 
 2853 static void dmi_mapped_address_size(u32 code)
 2854 {
 2855     if (code == 0)
 2856         pr_attr("Range Size", "Invalid");
 2857     else
 2858     {
 2859         u64 size;
 2860 
 2861         size.h = 0;
 2862         size.l = code;
 2863         dmi_print_memory_size("Range Size", size, 1);
 2864     }
 2865 }
 2866 
 2867 static void dmi_mapped_address_extended_size(u64 start, u64 end)
 2868 {
 2869     if (start.h == end.h && start.l == end.l)
 2870         pr_attr("Range Size", "Invalid");
 2871     else
 2872         dmi_print_memory_size("Range Size", u64_range(start, end), 0);
 2873 }
 2874 
 2875 /*
 2876  * 7.21 Memory Device Mapped Address (Type 20)
 2877  */
 2878 
 2879 static void dmi_mapped_address_row_position(u8 code)
 2880 {
 2881     if (code == 0)
 2882         pr_attr("Partition Row Position", "%s", out_of_spec);
 2883     else if (code == 0xFF)
 2884         pr_attr("Partition Row Position", "Unknown");
 2885     else
 2886         pr_attr("Partition Row Position", "%u", code);
 2887 }
 2888 
 2889 static void dmi_mapped_address_interleave_position(u8 code)
 2890 {
 2891     if (code != 0)
 2892     {
 2893         if (code == 0xFF)
 2894             pr_attr("Interleave Position", "Unknown");
 2895         else
 2896             pr_attr("Interleave Position", "%u", code);
 2897     }
 2898 }
 2899 
 2900 static void dmi_mapped_address_interleaved_data_depth(u8 code)
 2901 {
 2902     if (code != 0)
 2903     {
 2904         if (code == 0xFF)
 2905             pr_attr("Interleaved Data Depth", "Unknown");
 2906         else
 2907             pr_attr("Interleaved Data Depth", "%u", code);
 2908     }
 2909 }
 2910 
 2911 /*
 2912  * 7.22 Built-in Pointing Device (Type 21)
 2913  */
 2914 
 2915 static const char *dmi_pointing_device_type(u8 code)
 2916 {
 2917     /* 7.22.1 */
 2918     static const char *type[] = {
 2919         "Other", /* 0x01 */
 2920         "Unknown",
 2921         "Mouse",
 2922         "Track Ball",
 2923         "Track Point",
 2924         "Glide Point",
 2925         "Touch Pad",
 2926         "Touch Screen",
 2927         "Optical Sensor" /* 0x09 */
 2928     };
 2929 
 2930     if (code >= 0x01 && code <= 0x09)
 2931         return type[code - 0x01];
 2932     return out_of_spec;
 2933 }
 2934 
 2935 static const char *dmi_pointing_device_interface(u8 code)
 2936 {
 2937     /* 7.22.2 */
 2938     static const char *interface[] = {
 2939         "Other", /* 0x01 */
 2940         "Unknown",
 2941         "Serial",
 2942         "PS/2",
 2943         "Infrared",
 2944         "HIP-HIL",
 2945         "Bus Mouse",
 2946         "ADB (Apple Desktop Bus)" /* 0x08 */
 2947     };
 2948     static const char *interface_0xA0[] = {
 2949         "Bus Mouse DB-9", /* 0xA0 */
 2950         "Bus Mouse Micro DIN",
 2951         "USB" /* 0xA2 */
 2952     };
 2953 
 2954     if (code >= 0x01 && code <= 0x08)
 2955         return interface[code - 0x01];
 2956     if (code >= 0xA0 && code <= 0xA2)
 2957         return interface_0xA0[code - 0xA0];
 2958     return out_of_spec;
 2959 }
 2960 
 2961 /*
 2962  * 7.23 Portable Battery (Type 22)
 2963  */
 2964 
 2965 static const char *dmi_battery_chemistry(u8 code)
 2966 {
 2967     /* 7.23.1 */
 2968     static const char *chemistry[] = {
 2969         "Other", /* 0x01 */
 2970         "Unknown",
 2971         "Lead Acid",
 2972         "Nickel Cadmium",
 2973         "Nickel Metal Hydride",
 2974         "Lithium Ion",
 2975         "Zinc Air",
 2976         "Lithium Polymer" /* 0x08 */
 2977     };
 2978 
 2979     if (code >= 0x01 && code <= 0x08)
 2980         return chemistry[code - 0x01];
 2981     return out_of_spec;
 2982 }
 2983 
 2984 static void dmi_battery_capacity(u16 code, u8 multiplier)
 2985 {
 2986     if (code == 0)
 2987         pr_attr("Design Capacity", "Unknown");
 2988     else
 2989         pr_attr("Design Capacity", "%u mWh", code * multiplier);
 2990 }
 2991 
 2992 static void dmi_battery_voltage(u16 code)
 2993 {
 2994     if (code == 0)
 2995         pr_attr("Design Voltage", "Unknown");
 2996     else
 2997         pr_attr("Design Voltage", "%u mV", code);
 2998 }
 2999 
 3000 static void dmi_battery_maximum_error(u8 code)
 3001 {
 3002     if (code == 0xFF)
 3003         pr_attr("Maximum Error", "Unknown");
 3004     else
 3005         pr_attr("Maximum Error", "%u%%", code);
 3006 }
 3007 
 3008 /*
 3009  * 7.24 System Reset (Type 23)
 3010  */
 3011 
 3012 /* code is assumed to be a 2-bit value */
 3013 static const char *dmi_system_reset_boot_option(u8 code)
 3014 {
 3015     static const char *option[] = {
 3016         out_of_spec, /* 0x0 */
 3017         "Operating System", /* 0x1 */
 3018         "System Utilities",
 3019         "Do Not Reboot" /* 0x3 */
 3020     };
 3021 
 3022     return option[code];
 3023 }
 3024 
 3025 static void dmi_system_reset_count(const char *attr, u16 code)
 3026 {
 3027     if (code == 0xFFFF)
 3028         pr_attr(attr, "Unknown");
 3029     else
 3030         pr_attr(attr, "%u", code);
 3031 }
 3032 
 3033 static void dmi_system_reset_timer(const char *attr, u16 code)
 3034 {
 3035     if (code == 0xFFFF)
 3036         pr_attr(attr, "Unknown");
 3037     else
 3038         pr_attr(attr, "%u min", code);
 3039 }
 3040 
 3041 /*
 3042  * 7.25 Hardware Security (Type 24)
 3043  */
 3044 
 3045 static const char *dmi_hardware_security_status(u8 code)
 3046 {
 3047     static const char *status[] = {
 3048         "Disabled", /* 0x00 */
 3049         "Enabled",
 3050         "Not Implemented",
 3051         "Unknown" /* 0x03 */
 3052     };
 3053 
 3054     return status[code];
 3055 }
 3056 
 3057 /*
 3058  * 7.26 System Power Controls (Type 25)
 3059  */
 3060 
 3061 static void dmi_power_controls_power_on(const u8 *p)
 3062 {
 3063     char time[15];
 3064     int off = 0;
 3065 
 3066     /* 7.26.1 */
 3067     if (dmi_bcd_range(p[0], 0x01, 0x12))
 3068         off += sprintf(time + off, "%02X", p[0]);
 3069     else
 3070         off += sprintf(time + off, "*");
 3071     if (dmi_bcd_range(p[1], 0x01, 0x31))
 3072         off += sprintf(time + off, "-%02X", p[1]);
 3073     else
 3074         off += sprintf(time + off, "-*");
 3075     if (dmi_bcd_range(p[2], 0x00, 0x23))
 3076         off += sprintf(time + off, " %02X", p[2]);
 3077     else
 3078         off += sprintf(time + off, " *");
 3079     if (dmi_bcd_range(p[3], 0x00, 0x59))
 3080         off += sprintf(time + off, ":%02X", p[3]);
 3081     else
 3082         off += sprintf(time + off, ":*");
 3083     if (dmi_bcd_range(p[4], 0x00, 0x59))
 3084         off += sprintf(time + off, ":%02X", p[4]);
 3085     else
 3086         off += sprintf(time + off, ":*");
 3087 
 3088     pr_attr("Next Scheduled Power-on", time);
 3089 }
 3090 
 3091 /*
 3092  * 7.27 Voltage Probe (Type 26)
 3093  */
 3094 
 3095 static const char *dmi_voltage_probe_location(u8 code)
 3096 {
 3097     /* 7.27.1 */
 3098     static const char *location[] = {
 3099         "Other", /* 0x01 */
 3100         "Unknown",
 3101         "Processor",
 3102         "Disk",
 3103         "Peripheral Bay",
 3104         "System Management Module",
 3105         "Motherboard",
 3106         "Memory Module",
 3107         "Processor Module",
 3108         "Power Unit",
 3109         "Add-in Card" /* 0x0B */
 3110     };
 3111 
 3112     if (code >= 0x01 && code <= 0x0B)
 3113         return location[code - 0x01];
 3114     return out_of_spec;
 3115 }
 3116 
 3117 static const char *dmi_probe_status(u8 code)
 3118 {
 3119     /* 7.27.1 */
 3120     static const char *status[] = {
 3121         "Other", /* 0x01 */
 3122         "Unknown",
 3123         "OK",
 3124         "Non-critical",
 3125         "Critical",
 3126         "Non-recoverable" /* 0x06 */
 3127     };
 3128 
 3129     if (code >= 0x01 && code <= 0x06)
 3130         return status[code - 0x01];
 3131     return out_of_spec;
 3132 }
 3133 
 3134 static void dmi_voltage_probe_value(const char *attr, u16 code)
 3135 {
 3136     if (code == 0x8000)
 3137         pr_attr(attr, "Unknown");
 3138     else
 3139         pr_attr(attr, "%.3f V", (float)(i16)code / 1000);
 3140 }
 3141 
 3142 static void dmi_voltage_probe_resolution(u16 code)
 3143 {
 3144     if (code == 0x8000)
 3145         pr_attr("Resolution", "Unknown");
 3146     else
 3147         pr_attr("Resolution", "%.1f mV", (float)code / 10);
 3148 }
 3149 
 3150 static void dmi_probe_accuracy(u16 code)
 3151 {
 3152     if (code == 0x8000)
 3153         pr_attr("Accuracy", "Unknown");
 3154     else
 3155         pr_attr("Accuracy", "%.2f%%", (float)code / 100);
 3156 }
 3157 
 3158 /*
 3159  * 7.28 Cooling Device (Type 27)
 3160  */
 3161 
 3162 static const char *dmi_cooling_device_type(u8 code)
 3163 {
 3164     /* 7.28.1 */
 3165     static const char *type[] = {
 3166         "Other", /* 0x01 */
 3167         "Unknown",
 3168         "Fan",
 3169         "Centrifugal Blower",
 3170         "Chip Fan",
 3171         "Cabinet Fan",
 3172         "Power Supply Fan",
 3173         "Heat Pipe",
 3174         "Integrated Refrigeration" /* 0x09 */
 3175     };
 3176     static const char *type_0x10[] = {
 3177         "Active Cooling", /* 0x10 */
 3178         "Passive Cooling" /* 0x11 */
 3179     };
 3180 
 3181     if (code >= 0x01 && code <= 0x09)
 3182         return type[code - 0x01];
 3183     if (code >= 0x10 && code <= 0x11)
 3184         return type_0x10[code - 0x10];
 3185     return out_of_spec;
 3186 }
 3187 
 3188 static void dmi_cooling_device_speed(u16 code)
 3189 {
 3190     if (code == 0x8000)
 3191         pr_attr("Nominal Speed", "Unknown Or Non-rotating");
 3192     else
 3193         pr_attr("Nominal Speed", "%u rpm", code);
 3194 }
 3195 
 3196 /*
 3197  * 7.29 Temperature Probe (Type 28)
 3198  */
 3199 
 3200 static const char *dmi_temperature_probe_location(u8 code)
 3201 {
 3202     /* 7.29.1 */
 3203     static const char *location[] = {
 3204         "Other", /* 0x01 */
 3205         "Unknown",
 3206         "Processor",
 3207         "Disk",
 3208         "Peripheral Bay",
 3209         "System Management Module",
 3210         "Motherboard",
 3211         "Memory Module",
 3212         "Processor Module",
 3213         "Power Unit",
 3214         "Add-in Card",
 3215         "Front Panel Board",
 3216         "Back Panel Board",
 3217         "Power System Board",
 3218         "Drive Back Plane" /* 0x0F */
 3219     };
 3220 
 3221     if (code >= 0x01 && code <= 0x0F)
 3222         return location[code - 0x01];
 3223     return out_of_spec;
 3224 }
 3225 
 3226 static void dmi_temperature_probe_value(const char *attr, u16 code)
 3227 {
 3228     if (code == 0x8000)
 3229         pr_attr(attr, "Unknown");
 3230     else
 3231         pr_attr(attr, "%.1f deg C", (float)(i16)code / 10);
 3232 }
 3233 
 3234 static void dmi_temperature_probe_resolution(u16 code)
 3235 {
 3236     if (code == 0x8000)
 3237         pr_attr("Resolution", "Unknown");
 3238     else
 3239         pr_attr("Resolution", "%.3f deg C", (float)code / 1000);
 3240 }
 3241 
 3242 /*
 3243  * 7.30 Electrical Current Probe (Type 29)
 3244  */
 3245 
 3246 static void dmi_current_probe_value(const char *attr, u16 code)
 3247 {
 3248     if (code == 0x8000)
 3249         pr_attr(attr, "Unknown");
 3250     else
 3251         pr_attr(attr, "%.3f A", (float)(i16)code / 1000);
 3252 }
 3253 
 3254 static void dmi_current_probe_resolution(u16 code)
 3255 {
 3256     if (code == 0x8000)
 3257         pr_attr("Resolution", "Unknown");
 3258     else
 3259         pr_attr("Resolution", "%.1f mA", (float)code / 10);
 3260 }
 3261 
 3262 /*
 3263  * 7.33 System Boot Information (Type 32)
 3264  */
 3265 
 3266 static const char *dmi_system_boot_status(u8 code)
 3267 {
 3268     static const char *status[] = {
 3269         "No errors detected", /* 0 */
 3270         "No bootable media",
 3271         "Operating system failed to load",
 3272         "Firmware-detected hardware failure",
 3273         "Operating system-detected hardware failure",
 3274         "User-requested boot",
 3275         "System security violation",
 3276         "Previously-requested image",
 3277         "System watchdog timer expired" /* 8 */
 3278     };
 3279 
 3280     if (code <= 8)
 3281         return status[code];
 3282     if (code >= 128 && code <= 191)
 3283         return "OEM-specific";
 3284     if (code >= 192)
 3285         return "Product-specific";
 3286     return out_of_spec;
 3287 }
 3288 
 3289 /*
 3290  * 7.34 64-bit Memory Error Information (Type 33)
 3291  */
 3292 
 3293 static void dmi_64bit_memory_error_address(const char *attr, u64 code)
 3294 {
 3295     if (code.h == 0x80000000 && code.l == 0x00000000)
 3296         pr_attr(attr, "Unknown");
 3297     else
 3298         pr_attr(attr, "0x%08X%08X", code.h, code.l);
 3299 }
 3300 
 3301 /*
 3302  * 7.35 Management Device (Type 34)
 3303  */
 3304 
 3305 /*
 3306  * Several boards have a bug where some type 34 structures have their
 3307  * length incorrectly set to 0x10 instead of 0x0B. This causes the
 3308  * first 5 characters of the device name to be trimmed. It's easy to
 3309  * check and fix, so do it, but warn.
 3310  */
 3311 static void dmi_fixup_type_34(struct dmi_header *h, int display)
 3312 {
 3313     u8 *p = h->data;
 3314 
 3315     /* Make sure the hidden data is ASCII only */
 3316     if (h->length == 0x10
 3317      && is_printable(p + 0x0B, 0x10 - 0x0B))
 3318     {
 3319         if (!(opt.flags & FLAG_QUIET) && display)
 3320             fprintf(stderr,
 3321                 "Invalid entry length (%u). Fixed up to %u.\n",
 3322                 0x10, 0x0B);
 3323         h->length = 0x0B;
 3324     }
 3325 }
 3326 
 3327 static const char *dmi_management_device_type(u8 code)
 3328 {
 3329     /* 7.35.1 */
 3330     static const char *type[] = {
 3331         "Other", /* 0x01 */
 3332         "Unknown",
 3333         "LM75",
 3334         "LM78",
 3335         "LM79",
 3336         "LM80",
 3337         "LM81",
 3338         "ADM9240",
 3339         "DS1780",
 3340         "MAX1617",
 3341         "GL518SM",
 3342         "W83781D",
 3343         "HT82H791" /* 0x0D */
 3344     };
 3345 
 3346     if (code >= 0x01 && code <= 0x0D)
 3347         return type[code - 0x01];
 3348     return out_of_spec;
 3349 }
 3350 
 3351 static const char *dmi_management_device_address_type(u8 code)
 3352 {
 3353     /* 7.35.2 */
 3354     static const char *type[] = {
 3355         "Other", /* 0x01 */
 3356         "Unknown",
 3357         "I/O Port",
 3358         "Memory",
 3359         "SMBus" /* 0x05 */
 3360     };
 3361 
 3362     if (code >= 0x01 && code <= 0x05)
 3363         return type[code - 0x01];
 3364     return out_of_spec;
 3365 }
 3366 
 3367 /*
 3368  * 7.38 Memory Channel (Type 37)
 3369  */
 3370 
 3371 static const char *dmi_memory_channel_type(u8 code)
 3372 {
 3373     /* 7.38.1 */
 3374     static const char *type[] = {
 3375         "Other", /* 0x01 */
 3376         "Unknown",
 3377         "RamBus",
 3378         "SyncLink" /* 0x04 */
 3379     };
 3380 
 3381     if (code >= 0x01 && code <= 0x04)
 3382         return type[code - 0x01];
 3383     return out_of_spec;
 3384 }
 3385 
 3386 static void dmi_memory_channel_devices(u8 count, const u8 *p)
 3387 {
 3388     char attr[18];
 3389     int i;
 3390 
 3391     for (i = 1; i <= count; i++)
 3392     {
 3393         sprintf(attr, "Device %hu Load", i);
 3394         pr_attr(attr, "%u", p[3 * i]);
 3395         if (!(opt.flags & FLAG_QUIET))
 3396         {
 3397             sprintf(attr, "Device %hu Handle", i);
 3398             pr_attr(attr, "0x%04X", WORD(p + 3 * i + 1));
 3399         }
 3400     }
 3401 }
 3402 
 3403 /*
 3404  * 7.39 IPMI Device Information (Type 38)
 3405  */
 3406 
 3407 static const char *dmi_ipmi_interface_type(u8 code)
 3408 {
 3409     /* 7.39.1 and IPMI 2.0, appendix C1, table C1-2 */
 3410     static const char *type[] = {
 3411         "Unknown", /* 0x00 */
 3412         "KCS (Keyboard Control Style)",
 3413         "SMIC (Server Management Interface Chip)",
 3414         "BT (Block Transfer)",
 3415         "SSIF (SMBus System Interface)" /* 0x04 */
 3416     };
 3417 
 3418     if (code <= 0x04)
 3419         return type[code];
 3420     return out_of_spec;
 3421 }
 3422 
 3423 static void dmi_ipmi_base_address(u8 type, const u8 *p, u8 lsb)
 3424 {
 3425     if (type == 0x04) /* SSIF */
 3426     {
 3427         pr_attr("Base Address", "0x%02X (SMBus)", (*p) >> 1);
 3428     }
 3429     else
 3430     {
 3431         u64 address = QWORD(p);
 3432         pr_attr("Base Address", "0x%08X%08X (%s)",
 3433             address.h, (address.l & ~1) | lsb,
 3434             address.l & 1 ? "I/O" : "Memory-mapped");
 3435     }
 3436 }
 3437 
 3438 /* code is assumed to be a 2-bit value */
 3439 static const char *dmi_ipmi_register_spacing(u8 code)
 3440 {
 3441     /* IPMI 2.0, appendix C1, table C1-1 */
 3442     static const char *spacing[] = {
 3443         "Successive Byte Boundaries", /* 0x00 */
 3444         "32-bit Boundaries",
 3445         "16-byte Boundaries", /* 0x02 */
 3446         out_of_spec /* 0x03 */
 3447     };
 3448 
 3449     return spacing[code];
 3450 }
 3451 
 3452 /*
 3453  * 7.40 System Power Supply (Type 39)
 3454  */
 3455 
 3456 static void dmi_power_supply_power(u16 code)
 3457 {
 3458     if (code == 0x8000)
 3459         pr_attr("Max Power Capacity", "Unknown");
 3460     else
 3461         pr_attr("Max Power Capacity", "%u W", (unsigned int)code);
 3462 }
 3463 
 3464 static const char *dmi_power_supply_type(u8 code)
 3465 {
 3466     /* 7.40.1 */
 3467     static const char *type[] = {
 3468         "Other", /* 0x01 */
 3469         "Unknown",
 3470         "Linear",
 3471         "Switching",
 3472         "Battery",
 3473         "UPS",
 3474         "Converter",
 3475         "Regulator" /* 0x08 */
 3476     };
 3477 
 3478     if (code >= 0x01 && code <= 0x08)
 3479         return type[code - 0x01];
 3480     return out_of_spec;
 3481 }
 3482 
 3483 static const char *dmi_power_supply_status(u8 code)
 3484 {
 3485     /* 7.40.1 */
 3486     static const char *status[] = {
 3487         "Other", /* 0x01 */
 3488         "Unknown",
 3489         "OK",
 3490         "Non-critical",
 3491         "Critical" /* 0x05 */
 3492     };
 3493 
 3494     if (code >= 0x01 && code <= 0x05)
 3495         return status[code - 0x01];
 3496     return out_of_spec;
 3497 }
 3498 
 3499 static const char *dmi_power_supply_range_switching(u8 code)
 3500 {
 3501     /* 7.40.1 */
 3502     static const char *switching[] = {
 3503         "Other", /* 0x01 */
 3504         "Unknown",
 3505         "Manual",
 3506         "Auto-switch",
 3507         "Wide Range",
 3508         "N/A" /* 0x06 */
 3509     };
 3510 
 3511     if (code >= 0x01 && code <= 0x06)
 3512         return switching[code - 0x01];
 3513     return out_of_spec;
 3514 }
 3515 
 3516 /*
 3517  * 7.41 Additional Information (Type 40)
 3518  *
 3519  * Proper support of this entry type would require redesigning a large part of
 3520  * the code, so I am waiting to see actual implementations of it to decide
 3521  * whether it's worth the effort.
 3522  */
 3523 
 3524 static void dmi_additional_info(const struct dmi_header *h)
 3525 {
 3526     u8 *p = h->data + 4;
 3527     u8 count = *p++;
 3528     u8 length;
 3529     int i, offset = 5;
 3530 
 3531     for (i = 0; i < count; i++)
 3532     {
 3533         pr_handle_name("Additional Information %d", i + 1);
 3534 
 3535         /* Check for short entries */
 3536         if (h->length < offset + 1) break;
 3537         length = p[0x00];
 3538         if (length < 0x05 || h->length < offset + length) break;
 3539 
 3540         pr_attr("Referenced Handle", "0x%04x",
 3541             WORD(p + 0x01));
 3542         pr_attr("Referenced Offset", "0x%02x",
 3543             p[0x03]);
 3544         pr_attr("String", "%s",
 3545             dmi_string(h, p[0x04]));
 3546 
 3547         switch (length - 0x05)
 3548         {
 3549             case 1:
 3550                 pr_attr("Value", "0x%02x", p[0x05]);
 3551                 break;
 3552             case 2:
 3553                 pr_attr("Value", "0x%04x", WORD(p + 0x05));
 3554                 break;
 3555             case 4:
 3556                 pr_attr("Value", "0x%08x", DWORD(p + 0x05));
 3557                 break;
 3558             default:
 3559                 pr_attr("Value", "Unexpected size");
 3560                 break;
 3561         }
 3562 
 3563         p += length;
 3564         offset += length;
 3565     }
 3566 }
 3567 
 3568 /*
 3569  * 7.43 Management Controller Host Interface (Type 42)
 3570  */
 3571 
 3572 static const char *dmi_management_controller_host_type(u8 code)
 3573 {
 3574     /* DMTF DSP0239 (MCTP) version 1.1.0 */
 3575     static const char *type[] = {
 3576         "KCS: Keyboard Controller Style", /* 0x02 */
 3577         "8250 UART Register Compatible",
 3578         "16450 UART Register Compatible",
 3579         "16550/16550A UART Register Compatible",
 3580         "16650/16650A UART Register Compatible",
 3581         "16750/16750A UART Register Compatible",
 3582         "16850/16850A UART Register Compatible" /* 0x08 */
 3583     };
 3584 
 3585     if (code >= 0x02 && code <= 0x08)
 3586         return type[code - 0x02];
 3587     if (code <= 0x3F)
 3588         return "MCTP";
 3589     if (code == 0x40)
 3590         return "Network";
 3591     if (code == 0xF0)
 3592         return "OEM";
 3593     return out_of_spec;
 3594 }
 3595 
 3596 /*
 3597  * 7.43.2: Protocol Record Types
 3598  */
 3599 static const char *dmi_protocol_record_type(u8 type)
 3600 {
 3601     const char *protocol[] = {
 3602         "Reserved",     /* 0x0 */
 3603         "Reserved",
 3604         "IPMI",
 3605         "MCTP",
 3606         "Redfish over IP",  /* 0x4 */
 3607     };
 3608 
 3609     if (type <= 0x4)
 3610         return protocol[type];
 3611     if (type == 0xF0)
 3612         return "OEM";
 3613     return out_of_spec;
 3614 }
 3615 
 3616 /*
 3617  * DSP0270: 8.6: Protocol IP Assignment types
 3618  */
 3619 static const char *dmi_protocol_assignment_type(u8 type)
 3620 {
 3621     const char *assignment[] = {
 3622         "Unknown",      /* 0x0 */
 3623         "Static",
 3624         "DHCP",
 3625         "AutoConf",
 3626         "Host Selected",    /* 0x4 */
 3627     };
 3628 
 3629     if (type <= 0x4)
 3630         return assignment[type];
 3631     return out_of_spec;
 3632 }
 3633 
 3634 /*
 3635  * DSP0270: 8.6: Protocol IP Address type
 3636  */
 3637 static const char *dmi_address_type(u8 type)
 3638 {
 3639     const char *addressformat[] = {
 3640         "Unknown",  /* 0x0 */
 3641         "IPv4",
 3642         "IPv6",     /* 0x2 */
 3643     };
 3644 
 3645     if (type <= 0x2)
 3646         return addressformat[type];
 3647     return out_of_spec;
 3648 }
 3649 
 3650 /*
 3651  *  DSP0270: 8.6 Protocol Address decode
 3652  */
 3653 static const char *dmi_address_decode(u8 *data, char *storage, u8 addrtype)
 3654 {
 3655     if (addrtype == 0x1) /* IPv4 */
 3656         return inet_ntop(AF_INET, data, storage, 64);
 3657     if (addrtype == 0x2) /* IPv6 */
 3658         return inet_ntop(AF_INET6, data, storage, 64);
 3659     return out_of_spec;
 3660 }
 3661 
 3662 /*
 3663  * DSP0270: 8.5: Parse the protocol record format
 3664  */
 3665 static void dmi_parse_protocol_record(u8 *rec)
 3666 {
 3667     u8 rid;
 3668     u8 rlen;
 3669     u8 *rdata;
 3670     char buf[64];
 3671     u8 assign_val;
 3672     u8 addrtype;
 3673     u8 hlen;
 3674     const char *addrstr;
 3675     const char *hname;
 3676     char attr[38];
 3677 
 3678     /* DSP0270: 8.5: Protocol Identifier */
 3679     rid = rec[0x0];
 3680     /* DSP0270: 8.5: Protocol Record Length */
 3681     rlen = rec[0x1];
 3682     /* DSP0270: 8.5: Protocol Record Data */
 3683     rdata = &rec[0x2];
 3684 
 3685     pr_attr("Protocol ID", "%02x (%s)", rid,
 3686         dmi_protocol_record_type(rid));
 3687 
 3688     /*
 3689      * Don't decode anything other than Redfish for now
 3690      * Note 0x4 is Redfish over IP in 7.43.2
 3691      * and DSP0270: 8.5
 3692      */
 3693     if (rid != 0x4)
 3694         return;
 3695 
 3696     /*
 3697      * Ensure that the protocol record is of sufficient length
 3698      * For RedFish that means rlen must be at least 91 bytes
 3699      * other protcols will need different length checks
 3700      */
 3701     if (rlen < 91)
 3702         return;
 3703 
 3704     /*
 3705      * DSP0270: 8.6: Redfish Over IP Service UUID
 3706      * Note: ver is hardcoded to 0x311 here just for
 3707      * convenience.  It could get passed from the SMBIOS
 3708      * header, but that's a lot of passing of pointers just
 3709      * to get that info, and the only thing it is used for is
 3710      * to determine the endianess of the field.  Since we only
 3711      * do this parsing on versions of SMBIOS after 3.1.1, and the
 3712      * endianess of the field is always little after version 2.6.0
 3713      * we can just pick a sufficiently recent version here.
 3714      */
 3715     dmi_system_uuid(pr_subattr, "Service UUID", &rdata[0], 0x311);
 3716 
 3717     /*
 3718      * DSP0270: 8.6: Redfish Over IP Host IP Assignment Type
 3719      * Note, using decimal indicies here, as the DSP0270
 3720      * uses decimal, so as to make it more comparable
 3721      */
 3722     assign_val = rdata[16];
 3723     pr_subattr("Host IP Assignment Type", "%s",
 3724         dmi_protocol_assignment_type(assign_val));
 3725 
 3726     /* DSP0270: 8.6: Redfish Over IP Host Address format */
 3727     addrtype = rdata[17];
 3728     addrstr = dmi_address_type(addrtype);
 3729     pr_subattr("Host IP Address Format", "%s",
 3730         addrstr);
 3731 
 3732     /* DSP0270: 8.6 IP Assignment types */
 3733     /* We only use the Host IP Address and Mask if the assignment type is static */
 3734     if (assign_val == 0x1 || assign_val == 0x3)
 3735     {
 3736         /* DSP0270: 8.6: the Host IPv[4|6] Address */
 3737         sprintf(attr, "%s Address", addrstr);
 3738         pr_subattr(attr, "%s",
 3739             dmi_address_decode(&rdata[18], buf, addrtype));
 3740 
 3741         /* DSP0270: 8.6: Prints the Host IPv[4|6] Mask */
 3742         sprintf(attr, "%s Mask", addrstr);
 3743         pr_subattr(attr, "%s",
 3744             dmi_address_decode(&rdata[34], buf, addrtype));
 3745     }
 3746 
 3747     /* DSP0270: 8.6: Get the Redfish Service IP Discovery Type */
 3748     assign_val = rdata[50];
 3749     /* Redfish Service IP Discovery type mirrors Host IP Assignment type */
 3750     pr_subattr("Redfish Service IP Discovery Type", "%s",
 3751         dmi_protocol_assignment_type(assign_val));
 3752 
 3753     /* DSP0270: 8.6: Get the Redfish Service IP Address Format */
 3754     addrtype = rdata[51];
 3755     addrstr = dmi_address_type(addrtype);
 3756     pr_subattr("Redfish Service IP Address Format", "%s",
 3757         addrstr);
 3758 
 3759     if (assign_val == 0x1 || assign_val == 0x3)
 3760     {
 3761         u16 port;
 3762         u32 vlan;
 3763 
 3764         /* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Address */
 3765         sprintf(attr, "%s Redfish Service Address", addrstr);
 3766         pr_subattr(attr, "%s",
 3767             dmi_address_decode(&rdata[52], buf,
 3768             addrtype));
 3769 
 3770         /* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Mask */
 3771         sprintf(attr, "%s Redfish Service Mask", addrstr);
 3772         pr_subattr(attr, "%s",
 3773             dmi_address_decode(&rdata[68], buf,
 3774             addrtype));
 3775 
 3776         /* DSP0270: 8.6: Redfish vlan and port info */
 3777         port = WORD(&rdata[84]);
 3778         vlan = DWORD(&rdata[86]);
 3779         pr_subattr("Redfish Service Port", "%hu", port);
 3780         pr_subattr("Redfish Service Vlan", "%u", vlan);
 3781     }
 3782 
 3783     /* DSP0270: 8.6: Redfish host length and name */
 3784     hlen = rdata[90];
 3785 
 3786     /*
 3787      * DSP0270: 8.6: The length of the host string + 91 (the minimum
 3788      * size of a protocol record) cannot exceed the record length
 3789      * (rec[0x1])
 3790      */
 3791     hname = (const char *)&rdata[91];
 3792     if (hlen + 91 > rlen)
 3793     {
 3794         hname = out_of_spec;
 3795         hlen = strlen(out_of_spec);
 3796     }
 3797     pr_subattr("Redfish Service Hostname", "%.*s", hlen, hname);
 3798 }
 3799 
 3800 /*
 3801  * DSP0270: 8.3: Device type ennumeration
 3802  */
 3803 static const char *dmi_parse_device_type(u8 type)
 3804 {
 3805     const char *devname[] = {
 3806         "USB",      /* 0x2 */
 3807         "PCI/PCIe", /* 0x3 */
 3808     };
 3809 
 3810     if (type >= 0x2 && type <= 0x3)
 3811         return devname[type - 0x2];
 3812     if (type >= 0x80)
 3813         return "OEM";
 3814     return out_of_spec;
 3815 }
 3816 
 3817 static void dmi_parse_controller_structure(const struct dmi_header *h)
 3818 {
 3819     int i;
 3820     u8 *data = h->data;
 3821     /* Host interface type */
 3822     u8 type;
 3823     /* Host Interface specific data length */
 3824     u8 len;
 3825     u8 count;
 3826     u32 total_read;
 3827 
 3828     /*
 3829      * Minimum length of this struct is 0xB bytes
 3830      */
 3831     if (h->length < 0xB)
 3832         return;
 3833 
 3834     /*
 3835      * Also need to ensure that the interface specific data length
 3836      * plus the size of the structure to that point don't exceed
 3837      * the defined length of the structure, or we will overrun its
 3838      * bounds
 3839      */
 3840     len = data[0x5];
 3841     total_read = len + 0x6;
 3842 
 3843     if (total_read > h->length)
 3844         return;
 3845 
 3846     type = data[0x4];
 3847     pr_attr("Host Interface Type", "%s",
 3848         dmi_management_controller_host_type(type));
 3849 
 3850     /*
 3851      * The following decodes are code for Network interface host types only
 3852      * As defined in DSP0270
 3853      */
 3854     if (type != 0x40)
 3855         return;
 3856 
 3857     if (len != 0)
 3858     {
 3859         /* DSP0270: 8.3 Table 2: Device Type */
 3860         type = data[0x6];
 3861 
 3862         pr_attr("Device Type", "%s",
 3863             dmi_parse_device_type(type));
 3864         if (type == 0x2 && len >= 5)
 3865         {
 3866             /* USB Device Type - need at least 6 bytes */
 3867             u8 *usbdata = &data[0x7];
 3868             /* USB Device Descriptor: idVendor */
 3869             pr_attr("idVendor", "0x%04x",
 3870                 WORD(&usbdata[0x0]));
 3871             /* USB Device Descriptor: idProduct */
 3872             pr_attr("idProduct", "0x%04x",
 3873                 WORD(&usbdata[0x2]));
 3874             /*
 3875              * USB Serial number is here, but its useless, don't
 3876              * bother decoding it
 3877              */
 3878         }
 3879         else if (type == 0x3 && len >= 9)
 3880         {
 3881             /* PCI Device Type - Need at least 8 bytes */
 3882             u8 *pcidata = &data[0x7];
 3883             /* PCI Device Descriptor: VendorID */
 3884             pr_attr("VendorID", "0x%04x",
 3885                 WORD(&pcidata[0x0]));
 3886             /* PCI Device Descriptor: DeviceID */
 3887             pr_attr("DeviceID", "0x%04x",
 3888                 WORD(&pcidata[0x2]));
 3889             /* PCI Device Descriptor: PCI SubvendorID */
 3890             pr_attr("SubVendorID", "0x%04x",
 3891                 WORD(&pcidata[0x4]));
 3892             /* PCI Device Descriptor: PCI SubdeviceID */
 3893             pr_attr("SubDeviceID", "0x%04x",
 3894                 WORD(&pcidata[0x6]));
 3895         }
 3896         else if (type == 0x4 && len >= 5)
 3897         {
 3898             /* OEM Device Type - Need at least 4 bytes */
 3899             u8 *oemdata = &data[0x7];
 3900             /* OEM Device Descriptor: IANA */
 3901             pr_attr("Vendor ID", "0x%02x:0x%02x:0x%02x:0x%02x",
 3902                 oemdata[0x0], oemdata[0x1],
 3903                 oemdata[0x2], oemdata[0x3]);
 3904         }
 3905         /* Don't mess with unknown types for now */
 3906     }
 3907 
 3908     /*
 3909      * DSP0270: 8.2 and 8.5: Protocol record count and protocol records
 3910      * Move to the Protocol Count.
 3911      */
 3912     data = &data[total_read];
 3913 
 3914     /*
 3915      * We've validated up to 0x6 + len bytes, but we need to validate
 3916      * the next byte below, the count value.
 3917      */
 3918     total_read++;
 3919     if (total_read > h->length)
 3920     {
 3921         fprintf(stderr,
 3922             "Total read length %d exceeds total structure length %d (handle 0x%04hx)\n",
 3923             total_read, h->length, h->handle);
 3924         return;
 3925     }
 3926 
 3927     /* Get the protocol records count */
 3928     count = data[0x0];
 3929     if (count)
 3930     {
 3931         u8 *rec = &data[0x1];
 3932         for (i = 0; i < count; i++)
 3933         {
 3934             /*
 3935              * Need to ensure that this record doesn't overrun
 3936              * the total length of the type 42 struct.  Note the +2
 3937              * is added for the two leading bytes of a protocol
 3938              * record representing the type and length bytes.
 3939              */
 3940             total_read += rec[1] + 2;
 3941             if (total_read > h->length)
 3942             {
 3943                 fprintf(stderr,
 3944                     "Total read length %d exceeds total structure length %d (handle 0x%04hx, record %d)\n",
 3945                     total_read, h->length, h->handle, i + 1);
 3946                 return;
 3947             }
 3948 
 3949             dmi_parse_protocol_record(rec);
 3950 
 3951             /*
 3952              * DSP0270: 8.6
 3953              * Each record is rec[1] bytes long, starting at the
 3954              * data byte immediately following the length field.
 3955              * That means we need to add the byte for the rec id,
 3956              * the byte for the length field, and the value of the
 3957              * length field itself.
 3958              */
 3959             rec += rec[1] + 2;
 3960         }
 3961     }
 3962 }
 3963 
 3964 /*
 3965  * 7.44 TPM Device (Type 43)
 3966  */
 3967 
 3968 static void dmi_tpm_vendor_id(const u8 *p)
 3969 {
 3970     char vendor_id[5];
 3971     int i;
 3972 
 3973     /* ASCII filtering */
 3974     for (i = 0; i < 4 && p[i] != 0; i++)
 3975     {
 3976         if (p[i] < 32 || p[i] >= 127)
 3977             vendor_id[i] = '.';
 3978         else
 3979             vendor_id[i] = p[i];
 3980     }
 3981 
 3982     /* Terminate the string */
 3983     vendor_id[i] = '\0';
 3984 
 3985     pr_attr("Vendor ID", "%s", vendor_id);
 3986 }
 3987 
 3988 static void dmi_tpm_characteristics(u64 code)
 3989 {
 3990     /* 7.1.1 */
 3991     static const char *characteristics[] = {
 3992         "TPM Device characteristics not supported", /* 2 */
 3993         "Family configurable via firmware update",
 3994         "Family configurable via platform software support",
 3995         "Family configurable via OEM proprietary mechanism" /* 5 */
 3996     };
 3997     int i;
 3998 
 3999     /*
 4000      * This isn't very clear what this bit is supposed to mean
 4001      */
 4002     if (code.l & (1 << 2))
 4003     {
 4004         pr_list_item("%s", characteristics[0]);
 4005         return;
 4006     }
 4007 
 4008     for (i = 3; i <= 5; i++)
 4009         if (code.l & (1 << i))
 4010             pr_list_item("%s", characteristics[i - 2]);
 4011 }
 4012 
 4013 /*
 4014  * Main
 4015  */
 4016 
 4017 static void dmi_decode(const struct dmi_header *h, u16 ver)
 4018 {
 4019     const u8 *data = h->data;
 4020 
 4021     /*
 4022      * Note: DMI types 37 and 42 are untested
 4023      */
 4024     switch (h->type)
 4025     {
 4026         case 0: /* 7.1 BIOS Information */
 4027             pr_handle_name("BIOS Information");
 4028             if (h->length < 0x12) break;
 4029             pr_attr("Vendor", "%s",
 4030                 dmi_string(h, data[0x04]));
 4031             pr_attr("Version", "%s",
 4032                 dmi_string(h, data[0x05]));
 4033             pr_attr("Release Date", "%s",
 4034                 dmi_string(h, data[0x08]));
 4035             /*
 4036              * On IA-64, the BIOS base address will read 0 because
 4037              * there is no BIOS. Skip the base address and the
 4038              * runtime size in this case.
 4039              */
 4040             if (WORD(data + 0x06) != 0)
 4041             {
 4042                 pr_attr("Address", "0x%04X0",
 4043                     WORD(data + 0x06));
 4044                 dmi_bios_runtime_size((0x10000 - WORD(data + 0x06)) << 4);
 4045             }
 4046             dmi_bios_rom_size(data[0x09], h->length < 0x1A ? 16 : WORD(data + 0x18));
 4047             pr_list_start("Characteristics", NULL);
 4048             dmi_bios_characteristics(QWORD(data + 0x0A));
 4049             pr_list_end();
 4050             if (h->length < 0x13) break;
 4051             dmi_bios_characteristics_x1(data[0x12]);
 4052             if (h->length < 0x14) break;
 4053             dmi_bios_characteristics_x2(data[0x13]);
 4054             if (h->length < 0x18) break;
 4055             if (data[0x14] != 0xFF && data[0x15] != 0xFF)
 4056                 pr_attr("BIOS Revision", "%u.%u",
 4057                     data[0x14], data[0x15]);
 4058             if (data[0x16] != 0xFF && data[0x17] != 0xFF)
 4059                 pr_attr("Firmware Revision", "%u.%u",
 4060                     data[0x16], data[0x17]);
 4061             break;
 4062 
 4063         case 1: /* 7.2 System Information */
 4064             pr_handle_name("System Information");
 4065             if (h->length < 0x08) break;
 4066             pr_attr("Manufacturer", "%s",
 4067                 dmi_string(h, data[0x04]));
 4068             pr_attr("Product Name", "%s",
 4069                 dmi_string(h, data[0x05]));
 4070             pr_attr("Version", "%s",
 4071                 dmi_string(h, data[0x06]));
 4072             pr_attr("Serial Number", "%s",
 4073                 dmi_string(h, data[0x07]));
 4074             if (h->length < 0x19) break;
 4075             dmi_system_uuid(pr_attr, "UUID", data + 0x08, ver);
 4076             pr_attr("Wake-up Type", "%s",
 4077                 dmi_system_wake_up_type(data[0x18]));
 4078             if (h->length < 0x1B) break;
 4079             pr_attr("SKU Number", "%s",
 4080                 dmi_string(h, data[0x19]));
 4081             pr_attr("Family", "%s",
 4082                 dmi_string(h, data[0x1A]));
 4083             break;
 4084 
 4085         case 2: /* 7.3 Base Board Information */
 4086             pr_handle_name("Base Board Information");
 4087             if (h->length < 0x08) break;
 4088             pr_attr("Manufacturer", "%s",
 4089                 dmi_string(h, data[0x04]));
 4090             pr_attr("Product Name", "%s",
 4091                 dmi_string(h, data[0x05]));
 4092             pr_attr("Version", "%s",
 4093                 dmi_string(h, data[0x06]));
 4094             pr_attr("Serial Number", "%s",
 4095                 dmi_string(h, data[0x07]));
 4096             if (h->length < 0x09) break;
 4097             pr_attr("Asset Tag", "%s",
 4098                 dmi_string(h, data[0x08]));
 4099             if (h->length < 0x0A) break;
 4100             dmi_base_board_features(data[0x09]);
 4101             if (h->length < 0x0E) break;
 4102             pr_attr("Location In Chassis", "%s",
 4103                 dmi_string(h, data[0x0A]));
 4104             if (!(opt.flags & FLAG_QUIET))
 4105                 pr_attr("Chassis Handle", "0x%04X",
 4106                     WORD(data + 0x0B));
 4107             pr_attr("Type", "%s",
 4108                 dmi_base_board_type(data[0x0D]));
 4109             if (h->length < 0x0F) break;
 4110             if (h->length < 0x0F + data[0x0E] * sizeof(u16)) break;
 4111             if (!(opt.flags & FLAG_QUIET))
 4112                 dmi_base_board_handles(data[0x0E], data + 0x0F);
 4113             break;
 4114 
 4115         case 3: /* 7.4 Chassis Information */
 4116             pr_handle_name("Chassis Information");
 4117             if (h->length < 0x09) break;
 4118             pr_attr("Manufacturer", "%s",
 4119                 dmi_string(h, data[0x04]));
 4120             pr_attr("Type", "%s",
 4121                 dmi_chassis_type(data[0x05]));
 4122             pr_attr("Lock", "%s",
 4123                 dmi_chassis_lock(data[0x05] >> 7));
 4124             pr_attr("Version", "%s",
 4125                 dmi_string(h, data[0x06]));
 4126             pr_attr("Serial Number", "%s",
 4127                 dmi_string(h, data[0x07]));
 4128             pr_attr("Asset Tag", "%s",
 4129                 dmi_string(h, data[0x08]));
 4130             if (h->length < 0x0D) break;
 4131             pr_attr("Boot-up State", "%s",
 4132                 dmi_chassis_state(data[0x09]));
 4133             pr_attr("Power Supply State", "%s",
 4134                 dmi_chassis_state(data[0x0A]));
 4135             pr_attr("Thermal State", "%s",
 4136                 dmi_chassis_state(data[0x0B]));
 4137             pr_attr("Security Status", "%s",
 4138                 dmi_chassis_security_status(data[0x0C]));
 4139             if (h->length < 0x11) break;
 4140             pr_attr("OEM Information", "0x%08X",
 4141                 DWORD(data + 0x0D));
 4142             if (h->length < 0x13) break;
 4143             dmi_chassis_height(data[0x11]);
 4144             dmi_chassis_power_cords(data[0x12]);
 4145             if (h->length < 0x15) break;
 4146             if (h->length < 0x15 + data[0x13] * data[0x14]) break;
 4147             dmi_chassis_elements(data[0x13], data[0x14], data + 0x15);
 4148             if (h->length < 0x16 + data[0x13] * data[0x14]) break;
 4149             pr_attr("SKU Number", "%s",
 4150                 dmi_string(h, data[0x15 + data[0x13] * data[0x14]]));
 4151             break;
 4152 
 4153         case 4: /* 7.5 Processor Information */
 4154             pr_handle_name("Processor Information");
 4155             if (h->length < 0x1A) break;
 4156             pr_attr("Socket Designation", "%s",
 4157                 dmi_string(h, data[0x04]));
 4158             pr_attr("Type", "%s",
 4159                 dmi_processor_type(data[0x05]));
 4160             pr_attr("Family", "%s",
 4161                 dmi_processor_family(h, ver));
 4162             pr_attr("Manufacturer", "%s",
 4163                 dmi_string(h, data[0x07]));
 4164             dmi_processor_id(h);
 4165             pr_attr("Version", "%s",
 4166                 dmi_string(h, data[0x10]));
 4167             dmi_processor_voltage("Voltage", data[0x11]);
 4168             dmi_processor_frequency("External Clock", data + 0x12);
 4169             dmi_processor_frequency("Max Speed", data + 0x14);
 4170             dmi_processor_frequency("Current Speed", data + 0x16);
 4171             if (data[0x18] & (1 << 6))
 4172                 pr_attr("Status", "Populated, %s",
 4173                     dmi_processor_status(data[0x18] & 0x07));
 4174             else
 4175                 pr_attr("Status", "Unpopulated");
 4176             pr_attr("Upgrade", "%s",
 4177                 dmi_processor_upgrade(data[0x19]));
 4178             if (h->length < 0x20) break;
 4179             if (!(opt.flags & FLAG_QUIET))
 4180             {
 4181                 dmi_processor_cache("L1 Cache Handle",
 4182                             WORD(data + 0x1A), "L1", ver);
 4183                 dmi_processor_cache("L2 Cache Handle",
 4184                             WORD(data + 0x1C), "L2", ver);
 4185                 dmi_processor_cache("L3 Cache Handle",
 4186                             WORD(data + 0x1E), "L3", ver);
 4187             }
 4188             if (h->length < 0x23) break;
 4189             pr_attr("Serial Number", "%s",
 4190                 dmi_string(h, data[0x20]));
 4191             pr_attr("Asset Tag", "%s",
 4192                 dmi_string(h, data[0x21]));
 4193             pr_attr("Part Number", "%s",
 4194                 dmi_string(h, data[0x22]));
 4195             if (h->length < 0x28) break;
 4196             if (data[0x23] != 0)
 4197                 pr_attr("Core Count", "%u",
 4198                     h->length >= 0x2C && data[0x23] == 0xFF ?
 4199                     WORD(data + 0x2A) : data[0x23]);
 4200             if (data[0x24] != 0)
 4201                 pr_attr("Core Enabled", "%u",
 4202                     h->length >= 0x2E && data[0x24] == 0xFF ?
 4203                     WORD(data + 0x2C) : data[0x24]);
 4204             if (data[0x25] != 0)
 4205                 pr_attr("Thread Count", "%u",
 4206                     h->length >= 0x30 && data[0x25] == 0xFF ?
 4207                     WORD(data + 0x2E) : data[0x25]);
 4208             dmi_processor_characteristics("Characteristics",
 4209                               WORD(data + 0x26));
 4210             break;
 4211 
 4212         case 5: /* 7.6 Memory Controller Information */
 4213             pr_handle_name("Memory Controller Information");
 4214             if (h->length < 0x0F) break;
 4215             pr_attr("Error Detecting Method", "%s",
 4216                 dmi_memory_controller_ed_method(data[0x04]));
 4217             dmi_memory_controller_ec_capabilities("Error Correcting Capabilities",
 4218                                   data[0x05]);
 4219             pr_attr("Supported Interleave", "%s",
 4220                 dmi_memory_controller_interleave(data[0x06]));
 4221             pr_attr("Current Interleave", "%s",
 4222                 dmi_memory_controller_interleave(data[0x07]));
 4223             pr_attr("Maximum Memory Module Size", "%u MB",
 4224                 1 << data[0x08]);
 4225             pr_attr("Maximum Total Memory Size", "%u MB",
 4226                 data[0x0E] * (1 << data[0x08]));
 4227             dmi_memory_controller_speeds("Supported Speeds",
 4228                              WORD(data + 0x09));
 4229             dmi_memory_module_types("Supported Memory Types",
 4230                         WORD(data + 0x0B), 0);
 4231             dmi_processor_voltage("Memory Module Voltage", data[0x0D]);
 4232             if (h->length < 0x0F + data[0x0E] * sizeof(u16)) break;
 4233             dmi_memory_controller_slots(data[0x0E], data + 0x0F);
 4234             if (h->length < 0x10 + data[0x0E] * sizeof(u16)) break;
 4235             dmi_memory_controller_ec_capabilities("Enabled Error Correcting Capabilities",
 4236                                   data[0x0F + data[0x0E] * sizeof(u16)]);
 4237             break;
 4238 
 4239         case 6: /* 7.7 Memory Module Information */
 4240             pr_handle_name("Memory Module Information");
 4241             if (h->length < 0x0C) break;
 4242             pr_attr("Socket Designation", "%s",
 4243                 dmi_string(h, data[0x04]));
 4244             dmi_memory_module_connections(data[0x05]);
 4245             dmi_memory_module_speed("Current Speed", data[0x06]);
 4246             dmi_memory_module_types("Type", WORD(data + 0x07), 1);
 4247             dmi_memory_module_size("Installed Size", data[0x09]);
 4248             dmi_memory_module_size("Enabled Size", data[0x0A]);
 4249             dmi_memory_module_error(data[0x0B]);
 4250             break;
 4251 
 4252         case 7: /* 7.8 Cache Information */
 4253             pr_handle_name("Cache Information");
 4254             if (h->length < 0x0F) break;
 4255             pr_attr("Socket Designation", "%s",
 4256                 dmi_string(h, data[0x04]));
 4257             pr_attr("Configuration", "%s, %s, Level %u",
 4258                 WORD(data + 0x05) & 0x0080 ? "Enabled" : "Disabled",
 4259                 WORD(data + 0x05) & 0x0008 ? "Socketed" : "Not Socketed",
 4260                 (WORD(data + 0x05) & 0x0007) + 1);
 4261             pr_attr("Operational Mode", "%s",
 4262                 dmi_cache_mode((WORD(data + 0x05) >> 8) & 0x0003));
 4263             pr_attr("Location", "%s",
 4264                 dmi_cache_location((WORD(data + 0x05) >> 5) & 0x0003));
 4265             if (h->length >= 0x1B)
 4266                 dmi_cache_size_2("Installed Size", DWORD(data + 0x17));
 4267             else
 4268                 dmi_cache_size("Installed Size", WORD(data + 0x09));
 4269             if (h->length >= 0x17)
 4270                 dmi_cache_size_2("Maximum Size", DWORD(data + 0x13));
 4271             else
 4272                 dmi_cache_size("Maximum Size", WORD(data + 0x07));
 4273             dmi_cache_types("Supported SRAM Types", WORD(data + 0x0B), 0);
 4274             dmi_cache_types("Installed SRAM Type", WORD(data + 0x0D), 1);
 4275             if (h->length < 0x13) break;
 4276             dmi_memory_module_speed("Speed", data[0x0F]);
 4277             pr_attr("Error Correction Type", "%s",
 4278                 dmi_cache_ec_type(data[0x10]));
 4279             pr_attr("System Type", "%s",
 4280                 dmi_cache_type(data[0x11]));
 4281             pr_attr("Associativity", "%s",
 4282                 dmi_cache_associativity(data[0x12]));
 4283             break;
 4284 
 4285         case 8: /* 7.9 Port Connector Information */
 4286             pr_handle_name("Port Connector Information");
 4287             if (h->length < 0x09) break;
 4288             pr_attr("Internal Reference Designator", "%s",
 4289                 dmi_string(h, data[0x04]));
 4290             pr_attr("Internal Connector Type", "%s",
 4291                 dmi_port_connector_type(data[0x05]));
 4292             pr_attr("External Reference Designator", "%s",
 4293                 dmi_string(h, data[0x06]));
 4294             pr_attr("External Connector Type", "%s",
 4295                 dmi_port_connector_type(data[0x07]));
 4296             pr_attr("Port Type", "%s",
 4297                 dmi_port_type(data[0x08]));
 4298             break;
 4299 
 4300         case 9: /* 7.10 System Slots */
 4301             pr_handle_name("System Slot Information");
 4302             if (h->length < 0x0C) break;
 4303             pr_attr("Designation", "%s",
 4304                 dmi_string(h, data[0x04]));
 4305             pr_attr("Type", "%s%s",
 4306                 dmi_slot_bus_width(data[0x06]),
 4307                 dmi_slot_type(data[0x05]));
 4308             pr_attr("Current Usage", "%s",
 4309                 dmi_slot_current_usage(data[0x07]));
 4310             pr_attr("Length", "%s",
 4311                 dmi_slot_length(data[0x08]));
 4312             dmi_slot_id(data[0x09], data[0x0A], data[0x05]);
 4313             if (h->length < 0x0D)
 4314                 dmi_slot_characteristics("Characteristics", data[0x0B], 0x00);
 4315             else
 4316                 dmi_slot_characteristics("Characteristics", data[0x0B], data[0x0C]);
 4317             if (h->length < 0x11) break;
 4318             dmi_slot_segment_bus_func(WORD(data + 0x0D), data[0x0F], data[0x10]);
 4319             if (h->length < 0x13) break;
 4320             pr_attr("Data Bus Width", "%u", data[0x11]);
 4321             pr_attr("Peer Devices", "%u", data[0x12]);
 4322             if (h->length - 0x13 >= data[0x12] * 5)
 4323                 dmi_slot_peers(data[0x12], data + 0x13);
 4324             break;
 4325 
 4326         case 10: /* 7.11 On Board Devices Information */
 4327             dmi_on_board_devices(h);
 4328             break;
 4329 
 4330         case 11: /* 7.12 OEM Strings */
 4331             pr_handle_name("OEM Strings");
 4332             if (h->length < 0x05) break;
 4333             dmi_oem_strings(h);
 4334             break;
 4335 
 4336         case 12: /* 7.13 System Configuration Options */
 4337             pr_handle_name("System Configuration Options");
 4338             if (h->length < 0x05) break;
 4339             dmi_system_configuration_options(h);
 4340             break;
 4341 
 4342         case 13: /* 7.14 BIOS Language Information */
 4343             pr_handle_name("BIOS Language Information");
 4344             if (h->length < 0x16) break;
 4345             if (ver >= 0x0201)
 4346             {
 4347                 pr_attr("Language Description Format", "%s",
 4348                     dmi_bios_language_format(data[0x05]));
 4349             }
 4350             pr_list_start("Installable Languages", "%u", data[0x04]);
 4351             dmi_bios_languages(h);
 4352             pr_list_end();
 4353             pr_attr("Currently Installed Language", "%s",
 4354                 dmi_string(h, data[0x15]));
 4355             break;
 4356 
 4357         case 14: /* 7.15 Group Associations */
 4358             pr_handle_name("Group Associations");
 4359             if (h->length < 0x05) break;
 4360             pr_attr("Name", "%s",
 4361                 dmi_string(h, data[0x04]));
 4362             pr_list_start("Items", "%u",
 4363                 (h->length - 0x05) / 3);
 4364             dmi_group_associations_items((h->length - 0x05) / 3, data + 0x05);
 4365             pr_list_end();
 4366             break;
 4367 
 4368         case 15: /* 7.16 System Event Log */
 4369             pr_handle_name("System Event Log");
 4370             if (h->length < 0x14) break;
 4371             pr_attr("Area Length", "%u bytes",
 4372                 WORD(data + 0x04));
 4373             pr_attr("Header Start Offset", "0x%04X",
 4374                 WORD(data + 0x06));
 4375             if (WORD(data + 0x08) - WORD(data + 0x06))
 4376                 pr_attr("Header Length", "%u byte%s",
 4377                     WORD(data + 0x08) - WORD(data + 0x06),
 4378                     WORD(data + 0x08) - WORD(data + 0x06) > 1 ? "s" : "");
 4379             pr_attr("Data Start Offset", "0x%04X",
 4380                 WORD(data + 0x08));
 4381             pr_attr("Access Method", "%s",
 4382                 dmi_event_log_method(data[0x0A]));
 4383             dmi_event_log_address(data[0x0A], data + 0x10);
 4384             dmi_event_log_status(data[0x0B]);
 4385             pr_attr("Change Token", "0x%08X",
 4386                 DWORD(data + 0x0C));
 4387             if (h->length < 0x17) break;
 4388             pr_attr("Header Format", "%s",
 4389                 dmi_event_log_header_type(data[0x14]));
 4390             pr_attr("Supported Log Type Descriptors", "%u",
 4391                 data[0x15]);
 4392             if (h->length < 0x17 + data[0x15] * data[0x16]) break;
 4393             dmi_event_log_descriptors(data[0x15], data[0x16], data + 0x17);
 4394             break;
 4395 
 4396         case 16: /* 7.17 Physical Memory Array */
 4397             pr_handle_name("Physical Memory Array");
 4398             if (h->length < 0x0F) break;
 4399             pr_attr("Location", "%s",
 4400                 dmi_memory_array_location(data[0x04]));
 4401             pr_attr("Use", "%s",
 4402                 dmi_memory_array_use(data[0x05]));
 4403             pr_attr("Error Correction Type", "%s",
 4404                 dmi_memory_array_ec_type(data[0x06]));
 4405             if (DWORD(data + 0x07) == 0x80000000)
 4406             {
 4407                 if (h->length < 0x17)
 4408                     pr_attr("Maximum Capacity", "Unknown");
 4409                 else
 4410                     dmi_print_memory_size("Maximum Capacity",
 4411                                   QWORD(data + 0x0F), 0);
 4412             }
 4413             else
 4414             {
 4415                 u64 capacity;
 4416 
 4417                 capacity.h = 0;
 4418                 capacity.l = DWORD(data + 0x07);
 4419                 dmi_print_memory_size("Maximum Capacity",
 4420                               capacity, 1);
 4421             }
 4422             if (!(opt.flags & FLAG_QUIET))
 4423                 dmi_memory_array_error_handle(WORD(data + 0x0B));
 4424             pr_attr("Number Of Devices", "%u",
 4425                 WORD(data + 0x0D));
 4426             break;
 4427 
 4428         case 17: /* 7.18 Memory Device */
 4429             pr_handle_name("Memory Device");
 4430             if (h->length < 0x15) break;
 4431             if (!(opt.flags & FLAG_QUIET))
 4432             {
 4433                 pr_attr("Array Handle", "0x%04X",
 4434                     WORD(data + 0x04));
 4435                 dmi_memory_array_error_handle(WORD(data + 0x06));
 4436             }
 4437             dmi_memory_device_width("Total Width", WORD(data + 0x08));
 4438             dmi_memory_device_width("Data Width", WORD(data + 0x0A));
 4439             if (h->length >= 0x20 && WORD(data + 0x0C) == 0x7FFF)
 4440                 dmi_memory_device_extended_size(DWORD(data + 0x1C));
 4441             else
 4442                 dmi_memory_device_size(WORD(data + 0x0C));
 4443             pr_attr("Form Factor", "%s",
 4444                 dmi_memory_device_form_factor(data[0x0E]));
 4445             dmi_memory_device_set(data[0x0F]);
 4446             pr_attr("Locator", "%s",
 4447                 dmi_string(h, data[0x10]));
 4448             pr_attr("Bank Locator", "%s",
 4449                 dmi_string(h, data[0x11]));
 4450             pr_attr("Type", "%s",
 4451                 dmi_memory_device_type(data[0x12]));
 4452             dmi_memory_device_type_detail(WORD(data + 0x13));
 4453             if (h->length < 0x17) break;
 4454             dmi_memory_device_speed("Speed", WORD(data + 0x15));
 4455             if (h->length < 0x1B) break;
 4456             pr_attr("Manufacturer", "%s",
 4457                 dmi_string(h, data[0x17]));
 4458             pr_attr("Serial Number", "%s",
 4459                 dmi_string(h, data[0x18]));
 4460             pr_attr("Asset Tag", "%s",
 4461                 dmi_string(h, data[0x19]));
 4462             pr_attr("Part Number", "%s",
 4463                 dmi_string(h, data[0x1A]));
 4464             if (h->length < 0x1C) break;
 4465             if ((data[0x1B] & 0x0F) == 0)
 4466                 pr_attr("Rank", "Unknown");
 4467             else
 4468                 pr_attr("Rank", "%u", data[0x1B] & 0x0F);
 4469             if (h->length < 0x22) break;
 4470             dmi_memory_device_speed("Configured Memory Speed",
 4471                         WORD(data + 0x20));
 4472             if (h->length < 0x28) break;
 4473             dmi_memory_voltage_value("Minimum Voltage",
 4474                          WORD(data + 0x22));
 4475             dmi_memory_voltage_value("Maximum Voltage",
 4476                          WORD(data + 0x24));
 4477             dmi_memory_voltage_value("Configured Voltage",
 4478                          WORD(data + 0x26));
 4479             if (h->length < 0x34) break;
 4480             dmi_memory_technology(data[0x28]);
 4481             dmi_memory_operating_mode_capability(WORD(data + 0x29));
 4482             pr_attr("Firmware Version", "%s",
 4483                 dmi_string(h, data[0x2B]));
 4484             dmi_memory_manufacturer_id("Module Manufacturer ID",
 4485                            WORD(data + 0x2C));
 4486             dmi_memory_product_id("Module Product ID",
 4487                           WORD(data + 0x2E));
 4488             dmi_memory_manufacturer_id("Memory Subsystem Controller Manufacturer ID",
 4489                            WORD(data + 0x30));
 4490             dmi_memory_product_id("Memory Subsystem Controller Product ID",
 4491                           WORD(data + 0x32));
 4492             if (h->length < 0x3C) break;
 4493             dmi_memory_size("Non-Volatile Size", QWORD(data + 0x34));
 4494             if (h->length < 0x44) break;
 4495             dmi_memory_size("Volatile Size", QWORD(data + 0x3C));
 4496             if (h->length < 0x4C) break;
 4497             dmi_memory_size("Cache Size", QWORD(data + 0x44));
 4498             if (h->length < 0x54) break;
 4499             dmi_memory_size("Logical Size", QWORD(data + 0x4C));
 4500             break;
 4501 
 4502         case 18: /* 7.19 32-bit Memory Error Information */
 4503             pr_handle_name("32-bit Memory Error Information");
 4504             if (h->length < 0x17) break;
 4505             pr_attr("Type", "%s",
 4506                 dmi_memory_error_type(data[0x04]));
 4507             pr_attr("Granularity", "%s",
 4508                 dmi_memory_error_granularity(data[0x05]));
 4509             pr_attr("Operation", "%s",
 4510                 dmi_memory_error_operation(data[0x06]));
 4511             dmi_memory_error_syndrome(DWORD(data + 0x07));
 4512             dmi_32bit_memory_error_address("Memory Array Address",
 4513                                DWORD(data + 0x0B));
 4514             dmi_32bit_memory_error_address("Device Address",
 4515                                DWORD(data + 0x0F));
 4516             dmi_32bit_memory_error_address("Resolution",
 4517                                DWORD(data + 0x13));
 4518             break;
 4519 
 4520         case 19: /* 7.20 Memory Array Mapped Address */
 4521             pr_handle_name("Memory Array Mapped Address");
 4522             if (h->length < 0x0F) break;
 4523             if (h->length >= 0x1F && DWORD(data + 0x04) == 0xFFFFFFFF)
 4524             {
 4525                 u64 start, end;
 4526 
 4527                 start = QWORD(data + 0x0F);
 4528                 end = QWORD(data + 0x17);
 4529 
 4530                 pr_attr("Starting Address", "0x%08X%08Xk",
 4531                     start.h, start.l);
 4532                 pr_attr("Ending Address", "0x%08X%08Xk",
 4533                     end.h, end.l);
 4534                 dmi_mapped_address_extended_size(start, end);
 4535             }
 4536             else
 4537             {
 4538                 pr_attr("Starting Address", "0x%08X%03X",
 4539                     DWORD(data + 0x04) >> 2,
 4540                     (DWORD(data + 0x04) & 0x3) << 10);
 4541                 pr_attr("Ending Address", "0x%08X%03X",
 4542                     DWORD(data + 0x08) >> 2,
 4543                     ((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF);
 4544                 dmi_mapped_address_size(DWORD(data + 0x08) - DWORD(data + 0x04) + 1);
 4545             }
 4546             if (!(opt.flags & FLAG_QUIET))
 4547                 pr_attr("Physical Array Handle", "0x%04X",
 4548                     WORD(data + 0x0C));
 4549             pr_attr("Partition Width", "%u",
 4550                 data[0x0E]);
 4551             break;
 4552 
 4553         case 20: /* 7.21 Memory Device Mapped Address */
 4554             pr_handle_name("Memory Device Mapped Address");
 4555             if (h->length < 0x13) break;
 4556             if (h->length >= 0x23 && DWORD(data + 0x04) == 0xFFFFFFFF)
 4557             {
 4558                 u64 start, end;
 4559 
 4560                 start = QWORD(data + 0x13);
 4561                 end = QWORD(data + 0x1B);
 4562 
 4563                 pr_attr("Starting Address", "0x%08X%08Xk",
 4564                     start.h, start.l);
 4565                 pr_attr("Ending Address", "0x%08X%08Xk",
 4566                     end.h, end.l);
 4567                 dmi_mapped_address_extended_size(start, end);
 4568             }
 4569             else
 4570             {
 4571                 pr_attr("Starting Address", "0x%08X%03X",
 4572                     DWORD(data + 0x04) >> 2,
 4573                     (DWORD(data + 0x04) & 0x3) << 10);
 4574                 pr_attr("Ending Address", "0x%08X%03X",
 4575                     DWORD(data + 0x08) >> 2,
 4576                     ((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF);
 4577                 dmi_mapped_address_size(DWORD(data + 0x08) - DWORD(data + 0x04) + 1);
 4578             }
 4579             if (!(opt.flags & FLAG_QUIET))
 4580             {
 4581                 pr_attr("Physical Device Handle", "0x%04X",
 4582                     WORD(data + 0x0C));
 4583                 pr_attr("Memory Array Mapped Address Handle", "0x%04X",
 4584                     WORD(data + 0x0E));
 4585             }
 4586             dmi_mapped_address_row_position(data[0x10]);
 4587             dmi_mapped_address_interleave_position(data[0x11]);
 4588             dmi_mapped_address_interleaved_data_depth(data[0x12]);
 4589             break;
 4590 
 4591         case 21: /* 7.22 Built-in Pointing Device */
 4592             pr_handle_name("Built-in Pointing Device");
 4593             if (h->length < 0x07) break;
 4594             pr_attr("Type", "%s",
 4595                 dmi_pointing_device_type(data[0x04]));
 4596             pr_attr("Interface", "%s",
 4597                 dmi_pointing_device_interface(data[0x05]));
 4598             pr_attr("Buttons", "%u",
 4599                 data[0x06]);
 4600             break;
 4601 
 4602         case 22: /* 7.23 Portable Battery */
 4603             pr_handle_name("Portable Battery");
 4604             if (h->length < 0x10) break;
 4605             pr_attr("Location", "%s",
 4606                 dmi_string(h, data[0x04]));
 4607             pr_attr("Manufacturer", "%s",
 4608                 dmi_string(h, data[0x05]));
 4609             if (data[0x06] || h->length < 0x1A)
 4610                 pr_attr("Manufacture Date", "%s",
 4611                     dmi_string(h, data[0x06]));
 4612             if (data[0x07] || h->length < 0x1A)
 4613                 pr_attr("Serial Number", "%s",
 4614                     dmi_string(h, data[0x07]));
 4615             pr_attr("Name", "%s",
 4616                 dmi_string(h, data[0x08]));
 4617             if (data[0x09] != 0x02 || h->length < 0x1A)
 4618                 pr_attr("Chemistry", "%s",
 4619                     dmi_battery_chemistry(data[0x09]));
 4620             if (h->length < 0x16)
 4621                 dmi_battery_capacity(WORD(data + 0x0A), 1);
 4622             else
 4623                 dmi_battery_capacity(WORD(data + 0x0A), data[0x15]);
 4624             dmi_battery_voltage(WORD(data + 0x0C));
 4625             pr_attr("SBDS Version", "%s",
 4626                 dmi_string(h, data[0x0E]));
 4627             dmi_battery_maximum_error(data[0x0F]);
 4628             if (h->length < 0x1A) break;
 4629             if (data[0x07] == 0)
 4630                 pr_attr("SBDS Serial Number", "%04X",
 4631                     WORD(data + 0x10));
 4632             if (data[0x06] == 0)
 4633                 pr_attr("SBDS Manufacture Date", "%u-%02u-%02u",
 4634                     1980 + (WORD(data + 0x12) >> 9),
 4635                     (WORD(data + 0x12) >> 5) & 0x0F,
 4636                     WORD(data + 0x12) & 0x1F);
 4637             if (data[0x09] == 0x02)
 4638                 pr_attr("SBDS Chemistry", "%s",
 4639                     dmi_string(h, data[0x14]));
 4640             pr_attr("OEM-specific Information", "0x%08X",
 4641                 DWORD(data + 0x16));
 4642             break;
 4643 
 4644         case 23: /* 7.24 System Reset */
 4645             pr_handle_name("System Reset");
 4646             if (h->length < 0x0D) break;
 4647             pr_attr("Status", "%s",
 4648                 data[0x04] & (1 << 0) ? "Enabled" : "Disabled");
 4649             pr_attr("Watchdog Timer", "%s",
 4650                 data[0x04] & (1 << 5) ? "Present" : "Not Present");
 4651             if (!(data[0x04] & (1 << 5)))
 4652                 break;
 4653             pr_attr("Boot Option", "%s",
 4654                 dmi_system_reset_boot_option((data[0x04] >> 1) & 0x3));
 4655             pr_attr("Boot Option On Limit", "%s",
 4656                 dmi_system_reset_boot_option((data[0x04] >> 3) & 0x3));
 4657             dmi_system_reset_count("Reset Count", WORD(data + 0x05));
 4658             dmi_system_reset_count("Reset Limit", WORD(data + 0x07));
 4659             dmi_system_reset_timer("Timer Interval", WORD(data + 0x09));
 4660             dmi_system_reset_timer("Timeout", WORD(data + 0x0B));
 4661             break;
 4662 
 4663         case 24: /* 7.25 Hardware Security */
 4664             pr_handle_name("Hardware Security");
 4665             if (h->length < 0x05) break;
 4666             pr_attr("Power-On Password Status", "%s",
 4667                 dmi_hardware_security_status(data[0x04] >> 6));
 4668             pr_attr("Keyboard Password Status", "%s",
 4669                 dmi_hardware_security_status((data[0x04] >> 4) & 0x3));
 4670             pr_attr("Administrator Password Status", "%s",
 4671                 dmi_hardware_security_status((data[0x04] >> 2) & 0x3));
 4672             pr_attr("Front Panel Reset Status", "%s",
 4673                 dmi_hardware_security_status(data[0x04] & 0x3));
 4674             break;
 4675 
 4676         case 25: /* 7.26 System Power Controls */
 4677             pr_handle_name("System Power Controls");
 4678             if (h->length < 0x09) break;
 4679             dmi_power_controls_power_on(data + 0x04);
 4680             break;
 4681 
 4682         case 26: /* 7.27 Voltage Probe */
 4683             pr_handle_name("Voltage Probe");
 4684             if (h->length < 0x14) break;
 4685             pr_attr("Description", "%s",
 4686                 dmi_string(h, data[0x04]));
 4687             pr_attr("Location", "%s",
 4688                 dmi_voltage_probe_location(data[0x05] & 0x1f));
 4689             pr_attr("Status", "%s",
 4690                 dmi_probe_status(data[0x05] >> 5));
 4691             dmi_voltage_probe_value("Maximum Value", WORD(data + 0x06));
 4692             dmi_voltage_probe_value("Minimum Value", WORD(data + 0x08));
 4693             dmi_voltage_probe_resolution(WORD(data + 0x0A));
 4694             dmi_voltage_probe_value("Tolerance", WORD(data + 0x0C));
 4695             dmi_probe_accuracy(WORD(data + 0x0E));
 4696             pr_attr("OEM-specific Information", "0x%08X",
 4697                 DWORD(data + 0x10));
 4698             if (h->length < 0x16) break;
 4699             dmi_voltage_probe_value("Nominal Value", WORD(data + 0x14));
 4700             break;
 4701 
 4702         case 27: /* 7.28 Cooling Device */
 4703             pr_handle_name("Cooling Device");
 4704             if (h->length < 0x0C) break;
 4705             if (!(opt.flags & FLAG_QUIET) && WORD(data + 0x04) != 0xFFFF)
 4706                 pr_attr("Temperature Probe Handle", "0x%04X",
 4707                     WORD(data + 0x04));
 4708             pr_attr("Type", "%s",
 4709                 dmi_cooling_device_type(data[0x06] & 0x1f));
 4710             pr_attr("Status", "%s",
 4711                 dmi_probe_status(data[0x06] >> 5));
 4712             if (data[0x07] != 0x00)
 4713                 pr_attr("Cooling Unit Group", "%u",
 4714                     data[0x07]);
 4715             pr_attr("OEM-specific Information", "0x%08X",
 4716                 DWORD(data + 0x08));
 4717             if (h->length < 0x0E) break;
 4718             dmi_cooling_device_speed(WORD(data + 0x0C));
 4719             if (h->length < 0x0F) break;
 4720             pr_attr("Description", "%s", dmi_string(h, data[0x0E]));
 4721             break;
 4722 
 4723         case 28: /* 7.29 Temperature Probe */
 4724             pr_handle_name("Temperature Probe");
 4725             if (h->length < 0x14) break;
 4726             pr_attr("Description", "%s",
 4727                 dmi_string(h, data[0x04]));
 4728             pr_attr("Location", "%s",
 4729                 dmi_temperature_probe_location(data[0x05] & 0x1F));
 4730             pr_attr("Status", "%s",
 4731                 dmi_probe_status(data[0x05] >> 5));
 4732             dmi_temperature_probe_value("Maximum Value",
 4733                             WORD(data + 0x06));
 4734             dmi_temperature_probe_value("Minimum Value",
 4735                             WORD(data + 0x08));
 4736             dmi_temperature_probe_resolution(WORD(data + 0x0A));
 4737             dmi_temperature_probe_value("Tolerance",
 4738                             WORD(data + 0x0C));
 4739             dmi_probe_accuracy(WORD(data + 0x0E));
 4740             pr_attr("OEM-specific Information", "0x%08X",
 4741                 DWORD(data + 0x10));
 4742             if (h->length < 0x16) break;
 4743             dmi_temperature_probe_value("Nominal Value",
 4744                             WORD(data + 0x14));
 4745             break;
 4746 
 4747         case 29: /* 7.30 Electrical Current Probe */
 4748             pr_handle_name("Electrical Current Probe");
 4749             if (h->length < 0x14) break;
 4750             pr_attr("Description", "%s",
 4751                 dmi_string(h, data[0x04]));
 4752             pr_attr("Location", "%s",
 4753                 dmi_voltage_probe_location(data[5] & 0x1F));
 4754             pr_attr("Status", "%s",
 4755                 dmi_probe_status(data[0x05] >> 5));
 4756             dmi_current_probe_value("Maximum Value",
 4757                         WORD(data + 0x06));
 4758             dmi_current_probe_value("Minimum Value",
 4759                         WORD(data + 0x08));
 4760             dmi_current_probe_resolution(WORD(data + 0x0A));
 4761             dmi_current_probe_value("Tolerance",
 4762                         WORD(data + 0x0C));
 4763             dmi_probe_accuracy(WORD(data + 0x0E));
 4764             pr_attr("OEM-specific Information", "0x%08X",
 4765                 DWORD(data + 0x10));
 4766             if (h->length < 0x16) break;
 4767             dmi_current_probe_value("Nominal Value",
 4768                         WORD(data + 0x14));
 4769             break;
 4770 
 4771         case 30: /* 7.31 Out-of-band Remote Access */
 4772             pr_handle_name("Out-of-band Remote Access");
 4773             if (h->length < 0x06) break;
 4774             pr_attr("Manufacturer Name", "%s",
 4775                 dmi_string(h, data[0x04]));
 4776             pr_attr("Inbound Connection", "%s",
 4777                 data[0x05] & (1 << 0) ? "Enabled" : "Disabled");
 4778             pr_attr("Outbound Connection", "%s",
 4779                 data[0x05] & (1 << 1) ? "Enabled" : "Disabled");
 4780             break;
 4781 
 4782         case 31: /* 7.32 Boot Integrity Services Entry Point */
 4783             pr_handle_name("Boot Integrity Services Entry Point");
 4784             if (h->length < 0x1C) break;
 4785             pr_attr("Checksum", "%s",
 4786                 checksum(data, h->length) ? "OK" : "Invalid");
 4787             pr_attr("16-bit Entry Point Address", "%04X:%04X",
 4788                 DWORD(data + 0x08) >> 16,
 4789                 DWORD(data + 0x08) & 0xFFFF);
 4790             pr_attr("32-bit Entry Point Address", "0x%08X",
 4791                 DWORD(data + 0x0C));
 4792             break;
 4793 
 4794         case 32: /* 7.33 System Boot Information */
 4795             pr_handle_name("System Boot Information");
 4796             if (h->length < 0x0B) break;
 4797             pr_attr("Status", "%s",
 4798                 dmi_system_boot_status(data[0x0A]));
 4799             break;
 4800 
 4801         case 33: /* 7.34 64-bit Memory Error Information */
 4802             pr_handle_name("64-bit Memory Error Information");
 4803             if (h->length < 0x1F) break;
 4804             pr_attr("Type", "%s",
 4805                 dmi_memory_error_type(data[0x04]));
 4806             pr_attr("Granularity", "%s",
 4807                 dmi_memory_error_granularity(data[0x05]));
 4808             pr_attr("Operation", "%s",
 4809                 dmi_memory_error_operation(data[0x06]));
 4810             dmi_memory_error_syndrome(DWORD(data + 0x07));
 4811             dmi_64bit_memory_error_address("Memory Array Address",
 4812                                QWORD(data + 0x0B));
 4813             dmi_64bit_memory_error_address("Device Address",
 4814                                QWORD(data + 0x13));
 4815             dmi_32bit_memory_error_address("Resolution",
 4816                                DWORD(data + 0x1B));
 4817             break;
 4818 
 4819         case 34: /* 7.35 Management Device */
 4820             pr_handle_name("Management Device");
 4821             if (h->length < 0x0B) break;
 4822             pr_attr("Description", "%s",
 4823                 dmi_string(h, data[0x04]));
 4824             pr_attr("Type", "%s",
 4825                 dmi_management_device_type(data[0x05]));
 4826             pr_attr("Address", "0x%08X",
 4827                 DWORD(data + 0x06));
 4828             pr_attr("Address Type", "%s",
 4829                 dmi_management_device_address_type(data[0x0A]));
 4830             break;
 4831 
 4832         case 35: /* 7.36 Management Device Component */
 4833             pr_handle_name("Management Device Component");
 4834             if (h->length < 0x0B) break;
 4835             pr_attr("Description", "%s",
 4836                 dmi_string(h, data[0x04]));
 4837             if (!(opt.flags & FLAG_QUIET))
 4838             {
 4839                 pr_attr("Management Device Handle", "0x%04X",
 4840                     WORD(data + 0x05));
 4841                 pr_attr("Component Handle", "0x%04X",
 4842                     WORD(data + 0x07));
 4843                 if (WORD(data + 0x09) != 0xFFFF)
 4844                     pr_attr("Threshold Handle", "0x%04X",
 4845                         WORD(data + 0x09));
 4846             }
 4847             break;
 4848 
 4849         case 36: /* 7.37 Management Device Threshold Data */
 4850             pr_handle_name("Management Device Threshold Data");
 4851             if (h->length < 0x10) break;
 4852             if (WORD(data + 0x04) != 0x8000)
 4853                 pr_attr("Lower Non-critical Threshold", "%d",
 4854                     (i16)WORD(data + 0x04));
 4855             if (WORD(data + 0x06) != 0x8000)
 4856                 pr_attr("Upper Non-critical Threshold", "%d",
 4857                     (i16)WORD(data + 0x06));
 4858             if (WORD(data + 0x08) != 0x8000)
 4859                 pr_attr("Lower Critical Threshold", "%d",
 4860                     (i16)WORD(data + 0x08));
 4861             if (WORD(data + 0x0A) != 0x8000)
 4862                 pr_attr("Upper Critical Threshold", "%d",
 4863                     (i16)WORD(data + 0x0A));
 4864             if (WORD(data + 0x0C) != 0x8000)
 4865                 pr_attr("Lower Non-recoverable Threshold", "%d",
 4866                     (i16)WORD(data + 0x0C));
 4867             if (WORD(data + 0x0E) != 0x8000)
 4868                 pr_attr("Upper Non-recoverable Threshold", "%d",
 4869                     (i16)WORD(data + 0x0E));
 4870             break;
 4871 
 4872         case 37: /* 7.38 Memory Channel */
 4873             pr_handle_name("Memory Channel");
 4874             if (h->length < 0x07) break;
 4875             pr_attr("Type", "%s",
 4876                 dmi_memory_channel_type(data[0x04]));
 4877             pr_attr("Maximal Load", "%u",
 4878                 data[0x05]);
 4879             pr_attr("Devices", "%u",
 4880                 data[0x06]);
 4881             if (h->length < 0x07 + 3 * data