"Fossies" - the Fresh Open Source Software Archive

Member "dmidecode-3.3/dmioem.c" (14 Oct 2020, 13296 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 "dmioem.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  * Decoding of OEM-specific entries
    3  * This file is part of the dmidecode project.
    4  *
    5  *   Copyright (C) 2007-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 
   22 #include <stdio.h>
   23 #include <string.h>
   24 
   25 #include "types.h"
   26 #include "dmidecode.h"
   27 #include "dmioem.h"
   28 #include "dmioutput.h"
   29 
   30 /*
   31  * Globals for vendor-specific decodes
   32  */
   33 
   34 enum DMI_VENDORS
   35 {
   36     VENDOR_UNKNOWN,
   37     VENDOR_ACER,
   38     VENDOR_HP,
   39     VENDOR_HPE,
   40     VENDOR_IBM,
   41     VENDOR_LENOVO,
   42 };
   43 
   44 static enum DMI_VENDORS dmi_vendor = VENDOR_UNKNOWN;
   45 
   46 /*
   47  * Remember the system vendor for later use. We only actually store the
   48  * value if we know how to decode at least one specific entry type for
   49  * that vendor.
   50  */
   51 void dmi_set_vendor(const char *s)
   52 {
   53     int len;
   54 
   55     /*
   56      * Often DMI strings have trailing spaces. Ignore these
   57      * when checking for known vendor names.
   58      */
   59     len = strlen(s);
   60     while (len && s[len - 1] == ' ')
   61         len--;
   62 
   63     if (strncmp(s, "Acer", len) == 0)
   64         dmi_vendor = VENDOR_ACER;
   65     else if (strncmp(s, "HP", len) == 0 || strncmp(s, "Hewlett-Packard", len) == 0)
   66         dmi_vendor = VENDOR_HP;
   67     else if (strncmp(s, "HPE", len) == 0 || strncmp(s, "Hewlett Packard Enterprise", len) == 0)
   68         dmi_vendor = VENDOR_HPE;
   69     else if (strncmp(s, "IBM", len) == 0)
   70         dmi_vendor = VENDOR_IBM;
   71     else if (strncmp(s, "LENOVO", len) == 0)
   72         dmi_vendor = VENDOR_LENOVO;
   73 }
   74 
   75 /*
   76  * Acer-specific data structures are decoded here.
   77  */
   78 
   79 static int dmi_decode_acer(const struct dmi_header *h)
   80 {
   81     u8 *data = h->data;
   82     u16 cap;
   83 
   84     switch (h->type)
   85     {
   86         case 170:
   87             /*
   88              * Vendor Specific: Acer Hotkey Function
   89              *
   90              * Source: acer-wmi kernel driver
   91              *
   92              * Probably applies to some laptop models of other
   93              * brands, including Fujitsu-Siemens, Medion, Lenovo,
   94              * and eMachines.
   95              */
   96             pr_handle_name("Acer Hotkey Function");
   97             if (h->length < 0x0F) break;
   98             cap = WORD(data + 0x04);
   99             pr_attr("Function bitmap for Communication Button", "0x%04hx", cap);
  100             pr_subattr("WiFi", "%s", cap & 0x0001 ? "Yes" : "No");
  101             pr_subattr("3G", "%s", cap & 0x0040 ? "Yes" : "No");
  102             pr_subattr("WiMAX", "%s", cap & 0x0080 ? "Yes" : "No");
  103             pr_subattr("Bluetooth", "%s", cap & 0x0800 ? "Yes" : "No");
  104             pr_attr("Function bitmap for Application Button", "0x%04hx", WORD(data + 0x06));
  105             pr_attr("Function bitmap for Media Button", "0x%04hx", WORD(data + 0x08));
  106             pr_attr("Function bitmap for Display Button", "0x%04hx", WORD(data + 0x0A));
  107             pr_attr("Function bitmap for Others Button", "0x%04hx", WORD(data + 0x0C));
  108             pr_attr("Communication Function Key Number", "%d", data[0x0E]);
  109             break;
  110 
  111         default:
  112             return 0;
  113     }
  114     return 1;
  115 }
  116 
  117 /*
  118  * HPE-specific data structures are decoded here.
  119  *
  120  * Code contributed by John Cagle and Tyler Bell.
  121  */
  122 
  123 static void dmi_print_hp_net_iface_rec(u8 id, u8 bus, u8 dev, const u8 *mac)
  124 {
  125     /* Some systems do not provide an id. nic_ctr provides an artificial
  126      * id, and assumes the records will be provided "in order".  Also,
  127      * using 0xFF marker is not future proof. 256 NICs is a lot, but
  128      * 640K ought to be enough for anybody(said no one, ever).
  129      * */
  130     static u8 nic_ctr;
  131     char attr[8];
  132 
  133     if (id == 0xFF)
  134         id = ++nic_ctr;
  135 
  136     sprintf(attr, "NIC %hu", id);
  137     if (dev == 0x00 && bus == 0x00)
  138         pr_attr(attr, "Disabled");
  139     else if (dev == 0xFF && bus == 0xFF)
  140         pr_attr(attr, "Not Installed");
  141     else
  142     {
  143         pr_attr(attr, "PCI device %02x:%02x.%x, "
  144             "MAC address %02X:%02X:%02X:%02X:%02X:%02X",
  145             bus, dev >> 3, dev & 7,
  146             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  147     }
  148 }
  149 
  150 static int dmi_decode_hp(const struct dmi_header *h)
  151 {
  152     u8 *data = h->data;
  153     int nic, ptr;
  154     u32 feat;
  155     const char *company = (dmi_vendor == VENDOR_HP) ? "HP" : "HPE";
  156 
  157     switch (h->type)
  158     {
  159         case 204:
  160             /*
  161              * Vendor Specific: HPE ProLiant System/Rack Locator
  162              */
  163             pr_handle_name("%s ProLiant System/Rack Locator", company);
  164             if (h->length < 0x0B) break;
  165             pr_attr("Rack Name", "%s", dmi_string(h, data[0x04]));
  166             pr_attr("Enclosure Name", "%s", dmi_string(h, data[0x05]));
  167             pr_attr("Enclosure Model", "%s", dmi_string(h, data[0x06]));
  168             pr_attr("Enclosure Serial", "%s", dmi_string(h, data[0x0A]));
  169             pr_attr("Enclosure Bays", "%d", data[0x08]);
  170             pr_attr("Server Bay", "%s", dmi_string(h, data[0x07]));
  171             pr_attr("Bays Filled", "%d", data[0x09]);
  172             break;
  173 
  174         case 209:
  175         case 221:
  176             /*
  177              * Vendor Specific: HPE ProLiant NIC MAC Information
  178              *
  179              * This prints the BIOS NIC number,
  180              * PCI bus/device/function, and MAC address
  181              *
  182              * Type 209:
  183              * Offset |  Name  | Width | Description
  184              * -------------------------------------
  185              *  0x00  |  Type  | BYTE  | 0xD1, MAC Info
  186              *  0x01  | Length | BYTE  | Length of structure
  187              *  0x02  | Handle | WORD  | Unique handle
  188              *  0x04  | Dev No | BYTE  | PCI Device/Function No
  189              *  0x05  | Bus No | BYTE  | PCI Bus
  190              *  0x06  |   MAC  | 6B    | MAC addr
  191              *  0x0C  | NIC #2 | 8B    | Repeat 0x04-0x0B
  192              *
  193              * Type 221: is deprecated in the latest docs
  194              */
  195             pr_handle_name("%s %s", company, h->type == 221 ?
  196                        "BIOS iSCSI NIC PCI and MAC Information" :
  197                        "BIOS PXE NIC PCI and MAC Information");
  198             nic = 1;
  199             ptr = 4;
  200             while (h->length >= ptr + 8)
  201             {
  202                 dmi_print_hp_net_iface_rec(nic,
  203                                data[ptr + 0x01],
  204                                data[ptr],
  205                                &data[ptr + 0x02]);
  206                 nic++;
  207                 ptr += 8;
  208             }
  209             break;
  210 
  211         case 233:
  212             /*
  213              * Vendor Specific: HPE ProLiant NIC MAC Information
  214              *
  215              * This prints the BIOS NIC number,
  216              * PCI bus/device/function, and MAC address
  217              *
  218              * Offset |  Name  | Width | Description
  219              * -------------------------------------
  220              *  0x00  |  Type  | BYTE  | 0xE9, NIC structure
  221              *  0x01  | Length | BYTE  | Length of structure
  222              *  0x02  | Handle | WORD  | Unique handle
  223              *  0x04  | Grp No | WORD  | 0 for single segment
  224              *  0x06  | Bus No | BYTE  | PCI Bus
  225              *  0x07  | Dev No | BYTE  | PCI Device/Function No
  226              *  0x08  |   MAC  | 32B   | MAC addr padded w/ 0s
  227              *  0x28  | Port No| BYTE  | Each NIC maps to a Port
  228              */
  229             pr_handle_name("%s BIOS PXE NIC PCI and MAC Information",
  230                        company);
  231             if (h->length < 0x0E) break;
  232             /* If the record isn't long enough, we don't have an ID
  233              * use 0xFF to use the internal counter.
  234              * */
  235             nic = h->length > 0x28 ? data[0x28] : 0xFF;
  236             dmi_print_hp_net_iface_rec(nic, data[0x06], data[0x07],
  237                            &data[0x08]);
  238             break;
  239 
  240         case 212:
  241             /*
  242              * Vendor Specific: HPE 64-bit CRU Information
  243              *
  244              * Source: hpwdt kernel driver
  245              */
  246             pr_handle_name("%s 64-bit CRU Information", company);
  247             if (h->length < 0x18) break;
  248             if (is_printable(data + 0x04, 4))
  249                 pr_attr("Signature", "0x%08x (%c%c%c%c)",
  250                     DWORD(data + 0x04),
  251                     data[0x04], data[0x05],
  252                     data[0x06], data[0x07]);
  253             else
  254                 pr_attr("Signature", "0x%08x", DWORD(data + 0x04));
  255             if (DWORD(data + 0x04) == 0x55524324)
  256             {
  257                 u64 paddr = QWORD(data + 0x08);
  258                 paddr.l += DWORD(data + 0x14);
  259                 if (paddr.l < DWORD(data + 0x14))
  260                     paddr.h++;
  261                 pr_attr("Physical Address", "0x%08x%08x",
  262                     paddr.h, paddr.l);
  263                 pr_attr("Length", "0x%08x", DWORD(data + 0x10));
  264             }
  265             break;
  266 
  267         case 219:
  268             /*
  269              * Vendor Specific: HPE ProLiant Information
  270              *
  271              * Source: hpwdt kernel driver
  272              */
  273             pr_handle_name("%s ProLiant Information", company);
  274             if (h->length < 0x08) break;
  275             pr_attr("Power Features", "0x%08x", DWORD(data + 0x04));
  276             if (h->length < 0x0C) break;
  277             pr_attr("Omega Features", "0x%08x", DWORD(data + 0x08));
  278             if (h->length < 0x14) break;
  279             feat = DWORD(data + 0x10);
  280             pr_attr("Misc. Features", "0x%08x", feat);
  281             pr_subattr("iCRU", "%s", feat & 0x0001 ? "Yes" : "No");
  282             pr_subattr("UEFI", "%s", feat & 0x1400 ? "Yes" : "No");
  283             break;
  284 
  285         default:
  286             return 0;
  287     }
  288     return 1;
  289 }
  290 
  291 static int dmi_decode_ibm_lenovo(const struct dmi_header *h)
  292 {
  293     u8 *data = h->data;
  294 
  295     switch (h->type)
  296     {
  297         case 131:
  298             /*
  299              * Vendor Specific: ThinkVantage Technologies feature bits
  300              *
  301              * Source: Compal hel81 Service Manual Software Specification,
  302              *         documented under "System Management BIOS(SM BIOS)
  303              *         version 2.4 or greater"
  304              *
  305              * Offset |  Name         | Width   | Description
  306              * ----------------------------------------------
  307              *  0x00  | Type          | BYTE    | 0x83
  308              *  0x01  | Length        | BYTE    | 0x16
  309              *  0x02  | Handle        | WORD    | Varies
  310              *  0x04  | Version       | BYTE    | 0x01
  311              *  0x05  | TVT Structure | BYTEx16 | Each of the 128 bits represents a TVT feature:
  312              *        |               |         |  - bit 127 means diagnostics (PC Doctor) is available
  313              *        |               |         |    (http://www.pc-doctor.com/company/pr-articles/45-lenovo-introduces-thinkvantage-toolbox)
  314              *        |               |         |  - the rest (126-0) are reserved/unknown
  315              *
  316              * It must also be followed by a string containing
  317              * "TVT-Enablement". There exist other type 131 records
  318              * with different length and a different string, for
  319              * other purposes.
  320              */
  321 
  322             if (h->length != 0x16
  323              || strcmp(dmi_string(h, 1), "TVT-Enablement") != 0)
  324                 return 0;
  325 
  326             pr_handle_name("ThinkVantage Technologies");
  327             pr_attr("Version", "%u", data[0x04]);
  328             pr_attr("Diagnostics", "%s",
  329                 data[0x14] & 0x80 ? "Available" : "No");
  330             break;
  331 
  332         case 135:
  333             /*
  334              * Vendor Specific: Device Presence Detection bits
  335              *
  336              * Source: Compal hel81 Service Manual Software Specification,
  337              *         documented as "SMBIOS Type 135: Bulk for Lenovo
  338              *         Mobile PC Unique OEM Data" under appendix D.
  339              *
  340              * Offset |  Name                | Width | Description
  341              * ---------------------------------------------------
  342              *  0x00  | Type                 | BYTE  | 0x87
  343              *  0x01  | Length               | BYTE  | 0x0A
  344              *  0x02  | Handle               | WORD  | Varies
  345              *  0x04  | Signature            | WORD  | 0x5054 (ASCII for "TP")
  346              *  0x06  | OEM struct offset    | BYTE  | 0x07
  347              *  0x07  | OEM struct number    | BYTE  | 0x03, for this structure
  348              *  0x08  | OEM struct revision  | BYTE  | 0x01, for this format
  349              *  0x09  | Device presence bits | BYTE  | Each of the 8 bits indicates device presence:
  350              *        |                      |       |  - bit 0 indicates the presence of a fingerprint reader
  351              *        |                      |       |  - the rest (7-1) are reserved/unknown
  352              *
  353              * Other OEM struct number+rev combinations have been
  354              * seen in the wild but we don't know how to decode
  355              * them.
  356              */
  357 
  358             if (h->length < 0x0A || data[0x04] != 'T' || data[0x05] != 'P')
  359                 return 0;
  360 
  361             /* Bail out if not the expected format */
  362             if (data[0x06] != 0x07 || data[0x07] != 0x03 || data[0x08] != 0x01)
  363                 return 0;
  364 
  365             pr_handle_name("ThinkPad Device Presence Detection");
  366             pr_attr("Fingerprint Reader", "%s",
  367                 data[0x09] & 0x01 ? "Present" : "No");
  368             break;
  369 
  370         case 140:
  371             /*
  372              * Vendor Specific: ThinkPad Embedded Controller Program
  373              *
  374              * Source: some guesswork, and publicly available information;
  375              *         Lenovo's BIOS update READMEs often contain the ECP IDs
  376              *         which match the first string in this type.
  377              *
  378              * Offset |  Name                | Width  | Description
  379              * ----------------------------------------------------
  380              *  0x00  | Type                 | BYTE   | 0x8C
  381              *  0x01  | Length               | BYTE   |
  382              *  0x02  | Handle               | WORD   | Varies
  383              *  0x04  | Signature            | BYTEx6 | ASCII for "LENOVO"
  384              *  0x0A  | OEM struct offset    | BYTE   | 0x0B
  385              *  0x0B  | OEM struct number    | BYTE   | 0x07, for this structure
  386              *  0x0C  | OEM struct revision  | BYTE   | 0x01, for this format
  387              *  0x0D  | ECP version ID       | STRING |
  388              *  0x0E  | ECP release date     | STRING |
  389              */
  390 
  391             if (h->length < 0x0F || memcmp(data + 4, "LENOVO", 6) != 0)
  392                 return 0;
  393 
  394             /* Bail out if not the expected format */
  395             if (data[0x0A] != 0x0B || data[0x0B] != 0x07 || data[0x0C] != 0x01)
  396                 return 0;
  397 
  398             pr_handle_name("ThinkPad Embedded Controller Program");
  399             pr_attr("Version ID", "%s", dmi_string(h, 1));
  400             pr_attr("Release Date", "%s", dmi_string(h, 2));
  401             break;
  402 
  403         default:
  404             return 0;
  405     }
  406     return 1;
  407 }
  408 
  409 /*
  410  * Dispatch vendor-specific entries decoding
  411  * Return 1 if decoding was successful, 0 otherwise
  412  */
  413 int dmi_decode_oem(const struct dmi_header *h)
  414 {
  415     switch (dmi_vendor)
  416     {
  417         case VENDOR_HP:
  418         case VENDOR_HPE:
  419             return dmi_decode_hp(h);
  420         case VENDOR_ACER:
  421             return dmi_decode_acer(h);
  422         case VENDOR_IBM:
  423         case VENDOR_LENOVO:
  424             return dmi_decode_ibm_lenovo(h);
  425         default:
  426             return 0;
  427     }
  428 }