mirror of
https://git.jff.email/cgit/dmidecode.git
synced 2026-08-08 18:54:08 +00:00
New upstream version 3.2
This commit is contained in:
parent
a1e93482d9
commit
7c994b7f6b
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
biosdecode
|
||||
dmidecode
|
||||
ownership
|
||||
vpddecode
|
||||
*.o
|
||||
2
Makefile
2
Makefile
@ -134,7 +134,7 @@ uninstall-man :
|
||||
install-doc :
|
||||
$(INSTALL_DIR) $(DESTDIR)$(docdir)
|
||||
$(INSTALL_DATA) README $(DESTDIR)$(docdir)
|
||||
$(INSTALL_DATA) CHANGELOG $(DESTDIR)$(docdir)
|
||||
$(INSTALL_DATA) NEWS $(DESTDIR)$(docdir)
|
||||
$(INSTALL_DATA) AUTHORS $(DESTDIR)$(docdir)
|
||||
|
||||
uninstall-doc :
|
||||
|
||||
142
NEWS
Normal file
142
NEWS
Normal file
@ -0,0 +1,142 @@
|
||||
Version 3.2 (Wed Sep 14 2018)
|
||||
- [COMPATIBILITY] The UUID is now displayed using lowercase letters, per
|
||||
RFC 4122 (#53569). You must ensure that any code parsing it is
|
||||
case-insensitive.
|
||||
- Support for SMBIOS 3.2.0. This includes new processor names, new socket
|
||||
and port connector types, new system slot state and property, and support
|
||||
for non-volatile memory (NVDIMM).
|
||||
- Support for Redfish management controllers.
|
||||
- A new command line option to query a specific structure by its handle.
|
||||
- A new command line option to query the system family string.
|
||||
- Support for 3 ThinkPad-specific structures (patch #9642).
|
||||
- Support for HPE's new company name.
|
||||
- Support UEFI on FreeBSD.
|
||||
- Important bug fixes:
|
||||
Fix firmware version of TPM device
|
||||
Fix the HPE UEFI feature flag check
|
||||
- (biosdecode) A new command line option to fully decode PIR information
|
||||
(support request #109339).
|
||||
|
||||
Version 3.1 (Tue May 23 2017)
|
||||
- Support for SMBIOS 3.1.0 and 3.1.1. This includes new chassis types, new
|
||||
processor family names, new processor family upgrade names, and new slot
|
||||
types, as well as support of larger BIOS ROM sizes and cache sizes, and a
|
||||
new structure type (43, TPM Device.)
|
||||
- A new command line option to query OEM strings.
|
||||
- All error messages are now printed on stderr (#47274, #48158.)
|
||||
- Several bug fixes related to 64-bit entry points (#50037 and more.)
|
||||
- Important bug fixes:
|
||||
#46176 (Unexpected end of file error)
|
||||
#46066 (Crash with SIGBUS)
|
||||
- Various minor fixes, improvements and cleanups.
|
||||
|
||||
Version 3.0 (Thu Sep 03 2015)
|
||||
- Support for SMBIOS 3.0. This includes new chassis types, new
|
||||
processor family names, new processor family upgrade names, new slot
|
||||
types, and new memory device types.
|
||||
- Support for the new 64-bit entry point (_SM3_) defined in SMBIOS 3.0.
|
||||
- Support for the new kernel interface (as of Linux v4.2) as an
|
||||
alternative to relying /dev/mem to access the entry point and DMI
|
||||
table.
|
||||
- Decoding of Acer-specific DMI type 170.
|
||||
- Decoding of HP-specific DMI types 212, 219 and 233.
|
||||
- Various minor fixes and output format cleanups.
|
||||
|
||||
Version 2.12 (Wed Apr 17 2013)
|
||||
- Support of the SMBIOS 2.8.0 specification.
|
||||
|
||||
Version 2.11 (Wed Jan 19 2011)
|
||||
- Support of the SMBIOS 2.7.0 specification:
|
||||
- UEFI support
|
||||
- Virtual machine flags in BIOS characteristics
|
||||
- Limited support for the Management Controller Host Interface
|
||||
- Various fixes that address stability.
|
||||
|
||||
Version 2.10 (Sun Nov 23 2008)
|
||||
- Support for Solaris (x86 only, of course).
|
||||
- Possibility to dump the SMBIOS/DMI table to a small binary file
|
||||
(option --dump-bin).
|
||||
- Possibility to read the SMBIOS/DMI table from such binary files
|
||||
(option --from-dump).
|
||||
- Support for SMBIOS 2.6. This includes new chassis types, new
|
||||
processor family names, new processor family upgrade names, bus
|
||||
address for system slots, and a new entry type for on-board devices,
|
||||
amongst many other minor changes.
|
||||
- Support for DMI entry type 31 (Boot integrity services).
|
||||
- Many processor family names taken from the CIM Schema document.
|
||||
- (vpddecode) No longer ask users to report broken records.
|
||||
- (vpddecode) Fix --quiet option.
|
||||
|
||||
Version 2.9 (Mon Feb 26 2007)
|
||||
- Support of the SMBIOS 2.5 specification. It adds many enumerated
|
||||
values for recent hardware, as well as CPU core and thread count
|
||||
reporting.
|
||||
- Decoding of 3 HP-specific entries. More vendor-specific entries can
|
||||
be supported later if vendors contribute code or documentation.
|
||||
- Run-time detection of EFI, so that a single binary can support
|
||||
Intel-based Macintosh machines and regular x86 machines.
|
||||
- Better IA-64 support.
|
||||
- Fixes to the decoding of individual fields, including the CPU
|
||||
signature of recent CPU models.
|
||||
- (biosdecode) Support of the FJKEYINF entry point type (for Fujitsu laptops).
|
||||
- (vpddecode) The product name look-up table was dropped. It was unreliable
|
||||
and a burden to maintain.
|
||||
- biosdecode, ownership and vpddecode are no longer built on IA-64.
|
||||
|
||||
Version 2.8 (Sat Feb 04 2006)
|
||||
- Option --string has four additional keywords available:
|
||||
system-uuid, chassis-type, processor-family and processor-frequency.
|
||||
These needed additional work because, technically speaking, they are
|
||||
not DMI strings.
|
||||
- IPMI interface type SSIF was added. This is a new interface type
|
||||
defined by IPMI 2.0.
|
||||
- (vpddecode) New --string option, much similar in spirit to
|
||||
dmidecode's. Available keywords are bios-build-id, box-serial-number,
|
||||
motherboard-serial-number, machine-type-model and bios-release-date.
|
||||
- (vpddecode) 9 product names were added to the lookup table.
|
||||
- A few bug fixes, cleanups and minor improvements all around the place.
|
||||
|
||||
Version 2.7 (Thu Aug 04 2005)
|
||||
- New command line interface. For example, it is now possible to limit
|
||||
the output of dmidecode to a given DMI type, or to extract a single
|
||||
string from the DMI table. The documentation has been updated
|
||||
accordingly.
|
||||
- The default output of dmidecode was slightly modified to be more
|
||||
easily readable by humans. This might break tools parsing its output.
|
||||
Such tools may benefit from the new command line interface, although
|
||||
this interface shouldn't be considered stable until version 2.8.
|
||||
- (vpddecode) New command line interface.
|
||||
- (vpddecode) 6 product names were added.
|
||||
|
||||
Version 2.6 (Mon Feb 28 2005)
|
||||
- Fixes a 2 GB memory limit regression.
|
||||
- Basic command-line handling.
|
||||
- BeOS and Cygwin support.
|
||||
|
||||
Version 2.5 (Thu Nov 11 2004)
|
||||
- Code cleanups.
|
||||
- Compatibility fixes.
|
||||
- Documentation updates.
|
||||
|
||||
Version 2.4 (Fri Mar 19 2004)
|
||||
- Manual pages added.
|
||||
- (vpddecode) Many improvements.
|
||||
- A few fixes and minor improvements.
|
||||
|
||||
Version 2.3 (Sun Oct 19 2003)
|
||||
- Support of x86_64 systems.
|
||||
- Support of systems with 2 GB and more memory.
|
||||
- Loads of bug fixes and corrections.
|
||||
- New tool "vpddecode" added.
|
||||
|
||||
Version 2.2 (Fri Aug 08 2003)
|
||||
- Support of IA-64 systems.
|
||||
- Support of IBM and Fujitsu-Siemens laptops.
|
||||
- Many minor bug fixes.
|
||||
- New tool "ownership" added.
|
||||
|
||||
Version 2.1 (Tue Jun 10 2003)
|
||||
- Support of the SMBIOS 2.3.4 specification.
|
||||
- Better support of IPMI.
|
||||
- Minor bugs fixed.
|
||||
- Documentation added.
|
||||
2
README
2
README
@ -56,7 +56,7 @@ Each tool has a manual page, found in the "man" subdirectory. Manual pages
|
||||
are installed by "make install". See these manual pages for command line
|
||||
interface details and tool specific information.
|
||||
|
||||
For an history of the changes made to dmidecode, see the CHANGELOG file.
|
||||
For an history of the changes made to dmidecode, see the NEWS file.
|
||||
|
||||
If you need help, your best chances are to visit the web page (see the
|
||||
INSTALLATION section above) or to get in touch with the developers directly.
|
||||
|
||||
67
biosdecode.c
67
biosdecode.c
@ -73,12 +73,16 @@ struct opt
|
||||
{
|
||||
const char *devmem;
|
||||
unsigned int flags;
|
||||
unsigned char pir;
|
||||
};
|
||||
static struct opt opt;
|
||||
|
||||
#define FLAG_VERSION (1 << 0)
|
||||
#define FLAG_HELP (1 << 1)
|
||||
|
||||
#define PIR_SHORT 0
|
||||
#define PIR_FULL 1
|
||||
|
||||
struct bios_entry {
|
||||
const char *anchor;
|
||||
size_t anchor_len; /* computed */
|
||||
@ -351,7 +355,7 @@ static void pir_slot_number(u8 code)
|
||||
if (code == 0)
|
||||
printf(" on-board");
|
||||
else
|
||||
printf(" slot number %u", code);
|
||||
printf(" slot %u", code);
|
||||
}
|
||||
|
||||
static size_t pir_length(const u8 *p)
|
||||
@ -359,16 +363,26 @@ static size_t pir_length(const u8 *p)
|
||||
return WORD(p + 6);
|
||||
}
|
||||
|
||||
static void pir_link_bitmap(char letter, const u8 *p)
|
||||
{
|
||||
if (p[0] == 0) /* Not connected */
|
||||
return;
|
||||
|
||||
printf("\t\tINT%c#: Link 0x%02x, IRQ Bitmap", letter, p[0]);
|
||||
pir_irqs(WORD(p + 1));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int pir_decode(const u8 *p, size_t len)
|
||||
{
|
||||
int i;
|
||||
int i, n;
|
||||
|
||||
if (len < 32 || !checksum(p, WORD(p + 6)))
|
||||
return 0;
|
||||
|
||||
printf("PCI Interrupt Routing %u.%u present.\n",
|
||||
p[5], p[4]);
|
||||
printf("\tRouter ID: %02x:%02x.%1x\n",
|
||||
printf("\tRouter Device: %02x:%02x.%1x\n",
|
||||
p[8], p[9]>>3, p[9] & 0x07);
|
||||
printf("\tExclusive IRQs:");
|
||||
pir_irqs(WORD(p + 10));
|
||||
@ -380,38 +394,19 @@ static int pir_decode(const u8 *p, size_t len)
|
||||
printf("\tMiniport Data: 0x%08X\n",
|
||||
DWORD(p + 16));
|
||||
|
||||
for (i = 1; i <= (WORD(p + 6) - 32) / 16; i++)
|
||||
n = (len - 32) / 16;
|
||||
for (i = 1, p += 32; i <= n; i++, p += 16)
|
||||
{
|
||||
printf("\tSlot Entry %u: ID %02x:%02x,",
|
||||
i, p[(i + 1) * 16], p[(i + 1) * 16 + 1] >> 3);
|
||||
pir_slot_number(p[(i + 1) * 16 + 14]);
|
||||
printf("\tDevice: %02x:%02x,", p[0], p[1] >> 3);
|
||||
pir_slot_number(p[14]);
|
||||
printf("\n");
|
||||
/* printf("\tSlot Entry %u\n", i);
|
||||
printf("\t\tID: %02x:%02x\n",
|
||||
p[(i + 1) * 16], p[(i + 1) * 16 + 1] >> 3);
|
||||
printf("\t\tLink Value for INTA#: %u\n",
|
||||
p[(i + 1) * 16 + 2]);
|
||||
printf("\t\tIRQ Bitmap for INTA#:");
|
||||
pir_irqs(WORD(p + (i + 1) * 16 + 3));
|
||||
printf("\n");
|
||||
printf("\t\tLink Value for INTB#: %u\n",
|
||||
p[(i + 1) * 16 + 5]);
|
||||
printf("\t\tIRQ Bitmap for INTB#:");
|
||||
pir_irqs(WORD(p + (i + 1) * 16 + 6));
|
||||
printf("\n");
|
||||
printf("\t\tLink Value for INTC#: %u\n",
|
||||
p[(i + 1) * 16 + 8]);
|
||||
printf("\t\tIRQ Bitmap for INTC#:");
|
||||
pir_irqs(WORD(p + (i + 1) * 16 + 9));
|
||||
printf("\n");
|
||||
printf("\t\tLink Value for INTD#: %u\n",
|
||||
p[(i + 1) * 16 + 11]);
|
||||
printf("\t\tIRQ Bitmap for INTD#:");
|
||||
pir_irqs(WORD(p + (i + 1) * 16 + 12));
|
||||
printf("\n");
|
||||
printf("\t\tSlot Number:");
|
||||
pir_slot_number(p[(i + 1) * 16 + 14]);
|
||||
printf("\n");*/
|
||||
if (opt.pir == PIR_FULL)
|
||||
{
|
||||
pir_link_bitmap('A', p + 2);
|
||||
pir_link_bitmap('B', p + 5);
|
||||
pir_link_bitmap('C', p + 8);
|
||||
pir_link_bitmap('D', p + 11);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -616,6 +611,7 @@ static int parse_command_line(int argc, char * const argv[])
|
||||
const char *optstring = "d:hV";
|
||||
struct option longopts[] = {
|
||||
{ "dev-mem", required_argument, NULL, 'd' },
|
||||
{ "pir", required_argument, NULL, 'P' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
@ -627,6 +623,10 @@ static int parse_command_line(int argc, char * const argv[])
|
||||
case 'd':
|
||||
opt.devmem = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
if (strcmp(optarg, "full") == 0)
|
||||
opt.pir = PIR_FULL;
|
||||
break;
|
||||
case 'h':
|
||||
opt.flags |= FLAG_HELP;
|
||||
break;
|
||||
@ -646,6 +646,7 @@ static void print_help(void)
|
||||
"Usage: biosdecode [OPTIONS]\n"
|
||||
"Options are:\n"
|
||||
" -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n"
|
||||
" --pir full Decode the details of the PCI IRQ routing table\n"
|
||||
" -h, --help Display this help text and exit\n"
|
||||
" -V, --version Display the version and exit\n";
|
||||
|
||||
|
||||
653
dmidecode.c
653
dmidecode.c
@ -2,7 +2,7 @@
|
||||
* DMI Decode
|
||||
*
|
||||
* Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
|
||||
* Copyright (C) 2002-2017 Jean Delvare <jdelvare@suse.de>
|
||||
* Copyright (C) 2002-2018 Jean Delvare <jdelvare@suse.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -25,7 +25,7 @@
|
||||
* are deemed to be part of the source code.
|
||||
*
|
||||
* Unless specified otherwise, all references are aimed at the "System
|
||||
* Management BIOS Reference Specification, Version 3.1.1" document,
|
||||
* Management BIOS Reference Specification, Version 3.2.0" document,
|
||||
* available from http://www.dmtf.org/standards/smbios.
|
||||
*
|
||||
* Note to contributors:
|
||||
@ -56,6 +56,8 @@
|
||||
* - "PC Client Platform TPM Profile (PTP) Specification"
|
||||
* Family "2.0", Level 00, Revision 00.43, January 26, 2015
|
||||
* https://trustedcomputinggroup.org/pc-client-platform-tpm-profile-ptp-specification/
|
||||
* - "RedFish Host Interface Specification" (DMTF DSP0270)
|
||||
* https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -63,6 +65,12 @@
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <errno.h>
|
||||
#include <kenv.h>
|
||||
#endif
|
||||
|
||||
#include "version.h"
|
||||
#include "config.h"
|
||||
@ -75,7 +83,7 @@
|
||||
#define out_of_spec "<OUT OF SPEC>"
|
||||
static const char *bad_index = "<BAD INDEX>";
|
||||
|
||||
#define SUPPORTED_SMBIOS_VER 0x030101
|
||||
#define SUPPORTED_SMBIOS_VER 0x030200
|
||||
|
||||
#define FLAG_NO_FILE_OFFSET (1 << 0)
|
||||
#define FLAG_STOP_AT_EOT (1 << 1)
|
||||
@ -440,11 +448,11 @@ static void dmi_system_uuid(const u8 *p, u16 ver)
|
||||
* for older versions.
|
||||
*/
|
||||
if (ver >= 0x0206)
|
||||
printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
p[3], p[2], p[1], p[0], p[5], p[4], p[7], p[6],
|
||||
p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
|
||||
else
|
||||
printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
|
||||
p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
|
||||
}
|
||||
@ -878,6 +886,7 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
|
||||
{ 0xCC, "z/Architecture" },
|
||||
{ 0xCD, "Core i5" },
|
||||
{ 0xCE, "Core i3" },
|
||||
{ 0xCF, "Core i9" },
|
||||
|
||||
{ 0xD2, "C7-M" },
|
||||
{ 0xD3, "C7-D" },
|
||||
@ -1085,7 +1094,7 @@ static void dmi_processor_id(const struct dmi_header *h, const char *prefix)
|
||||
|| (type >= 0xA1 && type <= 0xB3) /* Intel */
|
||||
|| type == 0xB5 /* Intel */
|
||||
|| (type >= 0xB9 && type <= 0xC7) /* Intel */
|
||||
|| (type >= 0xCD && type <= 0xCE) /* Intel */
|
||||
|| (type >= 0xCD && type <= 0xCF) /* Intel */
|
||||
|| (type >= 0xD2 && type <= 0xDB) /* VIA, Intel */
|
||||
|| (type >= 0xDD && type <= 0xE0)) /* Intel */
|
||||
sig = 1;
|
||||
@ -1269,10 +1278,14 @@ static const char *dmi_processor_upgrade(u8 code)
|
||||
"Socket BGA1515",
|
||||
"Socket LGA3647-1",
|
||||
"Socket SP3",
|
||||
"Socket SP3r2" /* 0x38 */
|
||||
"Socket SP3r2",
|
||||
"Socket LGA2066",
|
||||
"Socket BGA1392",
|
||||
"Socket BGA1510",
|
||||
"Socket BGA1528" /* 0x3C */
|
||||
};
|
||||
|
||||
if (code >= 0x01 && code <= 0x38)
|
||||
if (code >= 0x01 && code <= 0x3C)
|
||||
return upgrade[code - 0x01];
|
||||
return out_of_spec;
|
||||
}
|
||||
@ -1685,7 +1698,8 @@ static const char *dmi_port_connector_type(u8 code)
|
||||
"Mini Jack (headphones)",
|
||||
"BNC",
|
||||
"IEEE 1394",
|
||||
"SAS/SATA Plug Receptacle" /* 0x22 */
|
||||
"SAS/SATA Plug Receptacle",
|
||||
"USB Type-C Receptacle" /* 0x23 */
|
||||
};
|
||||
static const char *type_0xA0[] = {
|
||||
"PC-98", /* 0xA0 */
|
||||
@ -1695,7 +1709,7 @@ static const char *dmi_port_connector_type(u8 code)
|
||||
"PC-98 Full" /* 0xA4 */
|
||||
};
|
||||
|
||||
if (code <= 0x22)
|
||||
if (code <= 0x23)
|
||||
return type[code];
|
||||
if (code >= 0xA0 && code <= 0xA4)
|
||||
return type_0xA0[code - 0xA0];
|
||||
@ -1870,10 +1884,11 @@ static const char *dmi_slot_current_usage(u8 code)
|
||||
"Other", /* 0x01 */
|
||||
"Unknown",
|
||||
"Available",
|
||||
"In Use" /* 0x04 */
|
||||
"In Use",
|
||||
"Unavailable" /* 0x05 */
|
||||
};
|
||||
|
||||
if (code >= 0x01 && code <= 0x04)
|
||||
if (code >= 0x01 && code <= 0x05)
|
||||
return usage[code - 0x01];
|
||||
return out_of_spec;
|
||||
}
|
||||
@ -1958,7 +1973,8 @@ static void dmi_slot_characteristics(u8 code1, u8 code2, const char *prefix)
|
||||
static const char *characteristics2[] = {
|
||||
"PME signal is supported", /* 0 */
|
||||
"Hot-plug devices are supported",
|
||||
"SMBus signal is supported" /* 2 */
|
||||
"SMBus signal is supported",
|
||||
"PCIe slot bifurcation is supported" /* 3 */
|
||||
};
|
||||
|
||||
if (code1 & (1 << 0))
|
||||
@ -1973,7 +1989,7 @@ static void dmi_slot_characteristics(u8 code1, u8 code2, const char *prefix)
|
||||
for (i = 1; i <= 7; i++)
|
||||
if (code1 & (1 << i))
|
||||
printf("%s%s\n", prefix, characteristics1[i - 1]);
|
||||
for (i = 0; i <= 2; i++)
|
||||
for (i = 0; i <= 3; i++)
|
||||
if (code2 & (1 << i))
|
||||
printf("%s%s\n", prefix, characteristics2[i]);
|
||||
}
|
||||
@ -2502,6 +2518,79 @@ static void dmi_memory_device_speed(u16 code)
|
||||
printf(" %u MT/s", code);
|
||||
}
|
||||
|
||||
static void dmi_memory_technology(u8 code)
|
||||
{
|
||||
/* 7.18.6 */
|
||||
static const char * const technology[] = {
|
||||
"Other", /* 0x01 */
|
||||
"Unknown",
|
||||
"DRAM",
|
||||
"NVDIMM-N",
|
||||
"NVDIMM-F",
|
||||
"NVDIMM-P",
|
||||
"Intel persistent memory" /* 0x07 */
|
||||
};
|
||||
if (code >= 0x01 && code <= 0x07)
|
||||
printf(" %s", technology[code - 0x01]);
|
||||
else
|
||||
printf(" %s", out_of_spec);
|
||||
}
|
||||
|
||||
static void dmi_memory_operating_mode_capability(u16 code)
|
||||
{
|
||||
/* 7.18.7 */
|
||||
static const char * const mode[] = {
|
||||
"Other", /* 1 */
|
||||
"Unknown",
|
||||
"Volatile memory",
|
||||
"Byte-accessible persistent memory",
|
||||
"Block-accessible persistent memory" /* 5 */
|
||||
};
|
||||
|
||||
if ((code & 0xFFFE) == 0)
|
||||
printf(" None");
|
||||
else {
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= 5; i++)
|
||||
if (code & (1 << i))
|
||||
printf(" %s", mode[i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void dmi_memory_manufacturer_id(u16 code)
|
||||
{
|
||||
/* 7.18.8 */
|
||||
/* 7.18.10 */
|
||||
/* LSB is 7-bit Odd Parity number of continuation codes */
|
||||
if (code == 0)
|
||||
printf(" Unknown");
|
||||
else
|
||||
printf(" Bank %d, Hex 0x%02X", (code & 0x7F) + 1, code >> 8);
|
||||
}
|
||||
|
||||
static void dmi_memory_product_id(u16 code)
|
||||
{
|
||||
/* 7.18.9 */
|
||||
/* 7.18.11 */
|
||||
if (code == 0)
|
||||
printf(" Unknown");
|
||||
else
|
||||
printf(" 0x%04X", code);
|
||||
}
|
||||
|
||||
static void dmi_memory_size(u64 code)
|
||||
{
|
||||
/* 7.18.12 */
|
||||
/* 7.18.13 */
|
||||
if (code.h == 0xFFFFFFFF && code.l == 0xFFFFFFFF)
|
||||
printf(" Unknown");
|
||||
else if (code.h == 0x0 && code.l == 0x0)
|
||||
printf(" None");
|
||||
else
|
||||
dmi_print_memory_size(code, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 7.19 32-bit Memory Error Information (Type 18)
|
||||
*/
|
||||
@ -3313,11 +3402,379 @@ static const char *dmi_management_controller_host_type(u8 code)
|
||||
|
||||
if (code >= 0x02 && code <= 0x08)
|
||||
return type[code - 0x02];
|
||||
if (code <= 0x3F)
|
||||
return "MCTP";
|
||||
if (code == 0x40)
|
||||
return "Network";
|
||||
if (code == 0xF0)
|
||||
return "OEM";
|
||||
return out_of_spec;
|
||||
}
|
||||
|
||||
/*
|
||||
* 7.43.2: Protocol Record Types
|
||||
*/
|
||||
static const char *dmi_protocol_record_type(u8 type)
|
||||
{
|
||||
const char *protocol[] = {
|
||||
"Reserved", /* 0x0 */
|
||||
"Reserved",
|
||||
"IPMI",
|
||||
"MCTP",
|
||||
"Redfish over IP", /* 0x4 */
|
||||
};
|
||||
|
||||
if (type <= 0x4)
|
||||
return protocol[type];
|
||||
if (type == 0xF0)
|
||||
return "OEM";
|
||||
return out_of_spec;
|
||||
}
|
||||
|
||||
/*
|
||||
* DSP0270: 8.6: Protocol IP Assignment types
|
||||
*/
|
||||
static const char *dmi_protocol_assignment_type(u8 type)
|
||||
{
|
||||
const char *assignment[] = {
|
||||
"Unknown", /* 0x0 */
|
||||
"Static",
|
||||
"DHCP",
|
||||
"AutoConf",
|
||||
"Host Selected", /* 0x4 */
|
||||
};
|
||||
|
||||
if (type <= 0x4)
|
||||
return assignment[type];
|
||||
return out_of_spec;
|
||||
}
|
||||
|
||||
/*
|
||||
* DSP0270: 8.6: Protocol IP Address type
|
||||
*/
|
||||
static const char *dmi_address_type(u8 type)
|
||||
{
|
||||
const char *addressformat[] = {
|
||||
"Unknown", /* 0x0 */
|
||||
"IPv4",
|
||||
"IPv6", /* 0x2 */
|
||||
};
|
||||
|
||||
if (type <= 0x2)
|
||||
return addressformat[type];
|
||||
return out_of_spec;
|
||||
}
|
||||
|
||||
/*
|
||||
* DSP0270: 8.6 Protocol Address decode
|
||||
*/
|
||||
static const char *dmi_address_decode(u8 *data, char *storage, u8 addrtype)
|
||||
{
|
||||
if (addrtype == 0x1) /* IPv4 */
|
||||
return inet_ntop(AF_INET, data, storage, 64);
|
||||
if (addrtype == 0x2) /* IPv6 */
|
||||
return inet_ntop(AF_INET6, data, storage, 64);
|
||||
return out_of_spec;
|
||||
}
|
||||
|
||||
/*
|
||||
* DSP0270: 8.5: Parse the protocol record format
|
||||
*/
|
||||
static void dmi_parse_protocol_record(const char *prefix, u8 *rec)
|
||||
{
|
||||
u8 rid;
|
||||
u8 rlen;
|
||||
u8 *rdata;
|
||||
char buf[64];
|
||||
u8 assign_val;
|
||||
u8 addrtype;
|
||||
u8 hlen;
|
||||
const char *addrstr;
|
||||
const char *hname;
|
||||
|
||||
/* DSP0270: 8.5: Protocol Identifier */
|
||||
rid = rec[0x0];
|
||||
/* DSP0270: 8.5: Protocol Record Length */
|
||||
rlen = rec[0x1];
|
||||
/* DSP0270: 8.5: Protocol Record Data */
|
||||
rdata = &rec[0x2];
|
||||
|
||||
printf("%s\tProtocol ID: %02x (%s)\n", prefix, rid,
|
||||
dmi_protocol_record_type(rid));
|
||||
|
||||
/*
|
||||
* Don't decode anything other than Redfish for now
|
||||
* Note 0x4 is Redfish over IP in 7.43.2
|
||||
* and DSP0270: 8.5
|
||||
*/
|
||||
if (rid != 0x4)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Ensure that the protocol record is of sufficient length
|
||||
* For RedFish that means rlen must be at least 91 bytes
|
||||
* other protcols will need different length checks
|
||||
*/
|
||||
if (rlen < 91)
|
||||
return;
|
||||
|
||||
/*
|
||||
* DSP0270: 8.6: Redfish Over IP Service UUID
|
||||
* Note: ver is hardcoded to 0x311 here just for
|
||||
* convenience. It could get passed from the SMBIOS
|
||||
* header, but that's a lot of passing of pointers just
|
||||
* to get that info, and the only thing it is used for is
|
||||
* to determine the endianess of the field. Since we only
|
||||
* do this parsing on versions of SMBIOS after 3.1.1, and the
|
||||
* endianess of the field is always little after version 2.6.0
|
||||
* we can just pick a sufficiently recent version here.
|
||||
*/
|
||||
printf("%s\t\tService UUID: ", prefix);
|
||||
dmi_system_uuid(&rdata[0], 0x311);
|
||||
printf("\n");
|
||||
|
||||
/*
|
||||
* DSP0270: 8.6: Redfish Over IP Host IP Assignment Type
|
||||
* Note, using decimal indicies here, as the DSP0270
|
||||
* uses decimal, so as to make it more comparable
|
||||
*/
|
||||
assign_val = rdata[16];
|
||||
printf("%s\t\tHost IP Assignment Type: %s\n", prefix,
|
||||
dmi_protocol_assignment_type(assign_val));
|
||||
|
||||
/* DSP0270: 8.6: Redfish Over IP Host Address format */
|
||||
addrtype = rdata[17];
|
||||
addrstr = dmi_address_type(addrtype);
|
||||
printf("%s\t\tHost IP Address Format: %s\n", prefix,
|
||||
addrstr);
|
||||
|
||||
/* DSP0270: 8.6 IP Assignment types */
|
||||
/* We only use the Host IP Address and Mask if the assignment type is static */
|
||||
if (assign_val == 0x1 || assign_val == 0x3)
|
||||
{
|
||||
/* DSP0270: 8.6: the Host IPv[4|6] Address */
|
||||
printf("%s\t\t%s Address: %s\n", prefix, addrstr,
|
||||
dmi_address_decode(&rdata[18], buf, addrtype));
|
||||
|
||||
/* DSP0270: 8.6: Prints the Host IPv[4|6] Mask */
|
||||
printf("%s\t\t%s Mask: %s\n", prefix, addrstr,
|
||||
dmi_address_decode(&rdata[34], buf, addrtype));
|
||||
}
|
||||
|
||||
/* DSP0270: 8.6: Get the Redfish Service IP Discovery Type */
|
||||
assign_val = rdata[50];
|
||||
/* Redfish Service IP Discovery type mirrors Host IP Assignment type */
|
||||
printf("%s\t\tRedfish Service IP Discovery Type: %s\n", prefix,
|
||||
dmi_protocol_assignment_type(assign_val));
|
||||
|
||||
/* DSP0270: 8.6: Get the Redfish Service IP Address Format */
|
||||
addrtype = rdata[51];
|
||||
addrstr = dmi_address_type(addrtype);
|
||||
printf("%s\t\tRedfish Service IP Address Format: %s\n", prefix,
|
||||
addrstr);
|
||||
|
||||
if (assign_val == 0x1 || assign_val == 0x3)
|
||||
{
|
||||
u16 port;
|
||||
u32 vlan;
|
||||
|
||||
/* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Address */
|
||||
printf("%s\t\t%s Redfish Service Address: %s\n", prefix,
|
||||
addrstr, dmi_address_decode(&rdata[52], buf,
|
||||
addrtype));
|
||||
|
||||
/* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Mask */
|
||||
printf("%s\t\t%s Redfish Service Mask: %s\n", prefix,
|
||||
addrstr, dmi_address_decode(&rdata[68], buf,
|
||||
addrtype));
|
||||
|
||||
/* DSP0270: 8.6: Redfish vlan and port info */
|
||||
port = WORD(&rdata[84]);
|
||||
vlan = DWORD(&rdata[86]);
|
||||
printf("%s\t\tRedfish Service Port: %hu\n", prefix, port);
|
||||
printf("%s\t\tRedfish Service Vlan: %u\n", prefix, vlan);
|
||||
}
|
||||
|
||||
/* DSP0270: 8.6: Redfish host length and name */
|
||||
hlen = rdata[90];
|
||||
|
||||
/*
|
||||
* DSP0270: 8.6: The length of the host string + 91 (the minimum
|
||||
* size of a protocol record) cannot exceed the record length
|
||||
* (rec[0x1])
|
||||
*/
|
||||
hname = (const char *)&rdata[91];
|
||||
if (hlen + 91 > rlen)
|
||||
{
|
||||
hname = out_of_spec;
|
||||
hlen = strlen(out_of_spec);
|
||||
}
|
||||
printf("%s\t\tRedfish Service Hostname: %*s\n", prefix, hlen, hname);
|
||||
}
|
||||
|
||||
/*
|
||||
* DSP0270: 8.3: Device type ennumeration
|
||||
*/
|
||||
static const char *dmi_parse_device_type(u8 type)
|
||||
{
|
||||
const char *devname[] = {
|
||||
"USB", /* 0x2 */
|
||||
"PCI/PCIe", /* 0x3 */
|
||||
};
|
||||
|
||||
if (type >= 0x2 && type <= 0x3)
|
||||
return devname[type - 0x2];
|
||||
if (type >= 0x80)
|
||||
return "OEM";
|
||||
return out_of_spec;
|
||||
}
|
||||
|
||||
static void dmi_parse_controller_structure(const struct dmi_header *h,
|
||||
const char *prefix)
|
||||
{
|
||||
int i;
|
||||
u8 *data = h->data;
|
||||
/* Host interface type */
|
||||
u8 type;
|
||||
/* Host Interface specific data length */
|
||||
u8 len;
|
||||
u8 count;
|
||||
u32 total_read;
|
||||
|
||||
/*
|
||||
* Minimum length of this struct is 0xB bytes
|
||||
*/
|
||||
if (h->length < 0xB)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Also need to ensure that the interface specific data length
|
||||
* plus the size of the structure to that point don't exceed
|
||||
* the defined length of the structure, or we will overrun its
|
||||
* bounds
|
||||
*/
|
||||
len = data[0x5];
|
||||
total_read = len + 0x6;
|
||||
|
||||
if (total_read > h->length)
|
||||
return;
|
||||
|
||||
type = data[0x4];
|
||||
printf("%sHost Interface Type: %s\n", prefix,
|
||||
dmi_management_controller_host_type(type));
|
||||
|
||||
/*
|
||||
* The following decodes are code for Network interface host types only
|
||||
* As defined in DSP0270
|
||||
*/
|
||||
if (type != 0x40)
|
||||
return;
|
||||
|
||||
if (len != 0)
|
||||
{
|
||||
/* DSP0270: 8.3 Table 2: Device Type */
|
||||
type = data[0x6];
|
||||
|
||||
printf("%sDevice Type: %s\n", prefix,
|
||||
dmi_parse_device_type(type));
|
||||
if (type == 0x2 && len >= 5)
|
||||
{
|
||||
/* USB Device Type - need at least 6 bytes */
|
||||
u8 *usbdata = &data[0x7];
|
||||
/* USB Device Descriptor: idVendor */
|
||||
printf("%s\tidVendor: 0x%04x\n", prefix,
|
||||
WORD(&usbdata[0x0]));
|
||||
/* USB Device Descriptor: idProduct */
|
||||
printf("%s\tidProduct: 0x%04x\n", prefix,
|
||||
WORD(&usbdata[0x2]));
|
||||
/*
|
||||
* USB Serial number is here, but its useless, don't
|
||||
* bother decoding it
|
||||
*/
|
||||
}
|
||||
else if (type == 0x3 && len >= 9)
|
||||
{
|
||||
/* PCI Device Type - Need at least 8 bytes */
|
||||
u8 *pcidata = &data[0x7];
|
||||
/* PCI Device Descriptor: VendorID */
|
||||
printf("%s\tVendorID: 0x%04x\n", prefix,
|
||||
WORD(&pcidata[0x0]));
|
||||
/* PCI Device Descriptor: DeviceID */
|
||||
printf("%s\tDeviceID: 0x%04x\n", prefix,
|
||||
WORD(&pcidata[0x2]));
|
||||
/* PCI Device Descriptor: PCI SubvendorID */
|
||||
printf("%s\tSubVendorID: 0x%04x\n", prefix,
|
||||
WORD(&pcidata[0x4]));
|
||||
/* PCI Device Descriptor: PCI SubdeviceID */
|
||||
printf("%s\tSubDeviceID: 0x%04x\n", prefix,
|
||||
WORD(&pcidata[0x6]));
|
||||
}
|
||||
else if (type == 0x4 && len >= 5)
|
||||
{
|
||||
/* OEM Device Type - Need at least 4 bytes */
|
||||
u8 *oemdata = &data[0x7];
|
||||
/* OEM Device Descriptor: IANA */
|
||||
printf("%s\tVendor ID: 0x%02x:0x%02x:0x%02x:0x%02x\n",
|
||||
prefix, oemdata[0x0], oemdata[0x1],
|
||||
oemdata[0x2], oemdata[0x3]);
|
||||
}
|
||||
/* Don't mess with unknown types for now */
|
||||
}
|
||||
|
||||
/*
|
||||
* DSP0270: 8.2 and 8.5: Protocol record count and protocol records
|
||||
* Move to the Protocol Count.
|
||||
*/
|
||||
data = &data[total_read];
|
||||
|
||||
/*
|
||||
* We've validated up to 0x6 + len bytes, but we need to validate
|
||||
* the next byte below, the count value.
|
||||
*/
|
||||
total_read++;
|
||||
if (total_read > h->length)
|
||||
{
|
||||
printf("%s\tWARN: Total read length %d exceeds total structure length %d\n",
|
||||
prefix, total_read, h->length);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the protocol records count */
|
||||
count = data[0x0];
|
||||
if (count)
|
||||
{
|
||||
u8 *rec = &data[0x1];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
/*
|
||||
* Need to ensure that this record doesn't overrun
|
||||
* the total length of the type 42 struct. Note the +2
|
||||
* is added for the two leading bytes of a protocol
|
||||
* record representing the type and length bytes.
|
||||
*/
|
||||
total_read += rec[1] + 2;
|
||||
if (total_read > h->length)
|
||||
{
|
||||
printf("%s\tWARN: Total read length %d exceeds total structure length %d\n",
|
||||
prefix, total_read, h->length);
|
||||
return;
|
||||
}
|
||||
|
||||
dmi_parse_protocol_record(prefix, rec);
|
||||
|
||||
/*
|
||||
* DSP0270: 8.6
|
||||
* Each record is rec[1] bytes long, starting at the
|
||||
* data byte immediately following the length field.
|
||||
* That means we need to add the byte for the rec id,
|
||||
* the byte for the length field, and the value of the
|
||||
* length field itself.
|
||||
*/
|
||||
rec += rec[1] + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 7.44 TPM Device (Type 43)
|
||||
*/
|
||||
@ -3889,7 +4346,7 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
printf("%u", data[0x1B] & 0x0F);
|
||||
printf("\n");
|
||||
if (h->length < 0x22) break;
|
||||
printf("\tConfigured Clock Speed:");
|
||||
printf("\tConfigured Memory Speed:");
|
||||
dmi_memory_device_speed(WORD(data + 0x20));
|
||||
printf("\n");
|
||||
if (h->length < 0x28) break;
|
||||
@ -3902,6 +4359,43 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
printf("\tConfigured Voltage:");
|
||||
dmi_memory_voltage_value(WORD(data + 0x26));
|
||||
printf("\n");
|
||||
if (h->length < 0x34) break;
|
||||
printf("\tMemory Technology:");
|
||||
dmi_memory_technology(data[0x28]);
|
||||
printf("\n");
|
||||
printf("\tMemory Operating Mode Capability:");
|
||||
dmi_memory_operating_mode_capability(WORD(data + 0x29));
|
||||
printf("\n");
|
||||
printf("\tFirmware Version: %s\n",
|
||||
dmi_string(h, data[0x2B]));
|
||||
printf("\tModule Manufacturer ID:");
|
||||
dmi_memory_manufacturer_id(WORD(data + 0x2C));
|
||||
printf("\n");
|
||||
printf("\tModule Product ID:");
|
||||
dmi_memory_product_id(WORD(data + 0x2E));
|
||||
printf("\n");
|
||||
printf("\tMemory Subsystem Controller Manufacturer ID:");
|
||||
dmi_memory_manufacturer_id(WORD(data + 0x30));
|
||||
printf("\n");
|
||||
printf("\tMemory Subsystem Controller Product ID:");
|
||||
dmi_memory_product_id(WORD(data + 0x32));
|
||||
printf("\n");
|
||||
if (h->length < 0x3C) break;
|
||||
printf("\tNon-Volatile Size:");
|
||||
dmi_memory_size(QWORD(data + 0x34));
|
||||
printf("\n");
|
||||
if (h->length < 0x44) break;
|
||||
printf("\tVolatile Size:");
|
||||
dmi_memory_size(QWORD(data + 0x3C));
|
||||
printf("\n");
|
||||
if (h->length < 0x4C) break;
|
||||
printf("\tCache Size:");
|
||||
dmi_memory_size(QWORD(data + 0x44));
|
||||
printf("\n");
|
||||
if (h->length < 0x54) break;
|
||||
printf("\tLogical Size:");
|
||||
dmi_memory_size(QWORD(data + 0x4C));
|
||||
printf("\n");
|
||||
break;
|
||||
|
||||
case 18: /* 7.19 32-bit Memory Error Information */
|
||||
@ -4467,22 +4961,27 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
|
||||
case 42: /* 7.43 Management Controller Host Interface */
|
||||
printf("Management Controller Host Interface\n");
|
||||
if (h->length < 0x05) break;
|
||||
printf("\tInterface Type: %s\n",
|
||||
dmi_management_controller_host_type(data[0x04]));
|
||||
/*
|
||||
* There you have a type-dependent, variable-length
|
||||
* part in the middle of the structure, with no
|
||||
* length specifier, so no easy way to decode the
|
||||
* common, final part of the structure. What a pity.
|
||||
*/
|
||||
if (h->length < 0x09) break;
|
||||
if (data[0x04] == 0xF0) /* OEM */
|
||||
if (ver < 0x0302)
|
||||
{
|
||||
printf("\tVendor ID: 0x%02X%02X%02X%02X\n",
|
||||
data[0x05], data[0x06], data[0x07],
|
||||
data[0x08]);
|
||||
if (h->length < 0x05) break;
|
||||
printf("\tInterface Type: %s\n",
|
||||
dmi_management_controller_host_type(data[0x04]));
|
||||
/*
|
||||
* There you have a type-dependent, variable-length
|
||||
* part in the middle of the structure, with no
|
||||
* length specifier, so no easy way to decode the
|
||||
* common, final part of the structure. What a pity.
|
||||
*/
|
||||
if (h->length < 0x09) break;
|
||||
if (data[0x04] == 0xF0) /* OEM */
|
||||
{
|
||||
printf("\tVendor ID: 0x%02X%02X%02X%02X\n",
|
||||
data[0x05], data[0x06], data[0x07],
|
||||
data[0x08]);
|
||||
}
|
||||
}
|
||||
else
|
||||
dmi_parse_controller_structure(h, "\t");
|
||||
break;
|
||||
|
||||
case 43: /* 7.44 TPM Device */
|
||||
@ -4506,7 +5005,7 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
case 0x02:
|
||||
printf("\tFirmware Revision: %u.%u\n",
|
||||
DWORD(data + 0x0A) >> 16,
|
||||
DWORD(data + 0x0A) && 0xFF);
|
||||
DWORD(data + 0x0A) & 0xFFFF);
|
||||
/*
|
||||
* We skip the next 4 bytes, as their
|
||||
* format is not standardized and their
|
||||
@ -4617,6 +5116,7 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
|
||||
|
||||
to_dmi_header(&h, data);
|
||||
display = ((opt.type == NULL || opt.type[h.type])
|
||||
&& (opt.handle == ~0U || opt.handle == h.handle)
|
||||
&& !((opt.flags & FLAG_QUIET) && (h.type == 126 || h.type == 127))
|
||||
&& !opt.string);
|
||||
|
||||
@ -4638,6 +5138,7 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
|
||||
/* In quiet mode, stop decoding at end of table marker */
|
||||
if ((opt.flags & FLAG_QUIET) && h.type == 127)
|
||||
@ -4648,6 +5149,22 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
|
||||
printf("Handle 0x%04X, DMI type %d, %d bytes\n",
|
||||
h.handle, h.type, h.length);
|
||||
|
||||
/* Look for the next handle */
|
||||
next = data + h.length;
|
||||
while ((unsigned long)(next - buf + 1) < len
|
||||
&& (next[0] != 0 || next[1] != 0))
|
||||
next++;
|
||||
next += 2;
|
||||
|
||||
/* Make sure the whole structure fits in the table */
|
||||
if ((unsigned long)(next - buf) > len)
|
||||
{
|
||||
if (display && !(opt.flags & FLAG_QUIET))
|
||||
printf("\t<TRUNCATED>\n\n");
|
||||
data = next;
|
||||
break;
|
||||
}
|
||||
|
||||
/* assign vendor for vendor-specific decodes later */
|
||||
if (h.type == 1 && h.length >= 5)
|
||||
dmi_set_vendor(dmi_string(&h, data[0x04]));
|
||||
@ -4656,33 +5173,21 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
|
||||
if (h.type == 34)
|
||||
dmi_fixup_type_34(&h, display);
|
||||
|
||||
/* look for the next handle */
|
||||
next = data + h.length;
|
||||
while ((unsigned long)(next - buf + 1) < len
|
||||
&& (next[0] != 0 || next[1] != 0))
|
||||
next++;
|
||||
next += 2;
|
||||
if (display)
|
||||
{
|
||||
if ((unsigned long)(next - buf) <= len)
|
||||
if (opt.flags & FLAG_DUMP)
|
||||
{
|
||||
if (opt.flags & FLAG_DUMP)
|
||||
{
|
||||
dmi_dump(&h, "\t");
|
||||
printf("\n");
|
||||
}
|
||||
else
|
||||
dmi_decode(&h, ver);
|
||||
dmi_dump(&h, "\t");
|
||||
printf("\n");
|
||||
}
|
||||
else if (!(opt.flags & FLAG_QUIET))
|
||||
printf("\t<TRUNCATED>\n\n");
|
||||
else
|
||||
dmi_decode(&h, ver);
|
||||
}
|
||||
else if (opt.string != NULL
|
||||
&& opt.string->type == h.type)
|
||||
dmi_table_string(&h, data, ver);
|
||||
|
||||
data = next;
|
||||
i++;
|
||||
|
||||
/* SMBIOS v3 requires stopping at this marker */
|
||||
if (h.type == 127 && (flags & FLAG_STOP_AT_EOT))
|
||||
@ -4812,6 +5317,15 @@ static int smbios3_decode(u8 *buf, const char *devmem, u32 flags)
|
||||
u32 ver;
|
||||
u64 offset;
|
||||
|
||||
/* Don't let checksum run beyond the buffer */
|
||||
if (buf[0x06] > 0x20)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Entry point length too large (%u bytes, expected %u).\n",
|
||||
(unsigned int)buf[0x06], 0x18U);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!checksum(buf, buf[0x06]))
|
||||
return 0;
|
||||
|
||||
@ -4850,6 +5364,15 @@ static int smbios_decode(u8 *buf, const char *devmem, u32 flags)
|
||||
{
|
||||
u16 ver;
|
||||
|
||||
/* Don't let checksum run beyond the buffer */
|
||||
if (buf[0x05] > 0x20)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Entry point length too large (%u bytes, expected %u).\n",
|
||||
(unsigned int)buf[0x05], 0x1FU);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!checksum(buf, buf[0x05])
|
||||
|| memcmp(buf + 0x10, "_DMI_", 5) != 0
|
||||
|| !checksum(buf + 0x10, 0x0F))
|
||||
@ -4934,13 +5457,19 @@ static int legacy_decode(u8 *buf, const char *devmem, u32 flags)
|
||||
#define EFI_NO_SMBIOS (-2)
|
||||
static int address_from_efi(off_t *address)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
FILE *efi_systab;
|
||||
const char *filename;
|
||||
char linebuf[64];
|
||||
#elif defined(__FreeBSD__)
|
||||
char addrstr[KENV_MVALLEN + 1];
|
||||
#endif
|
||||
const char *eptype;
|
||||
int ret;
|
||||
|
||||
*address = 0; /* Prevent compiler warning */
|
||||
|
||||
#if defined(__linux__)
|
||||
/*
|
||||
* Linux up to 2.6.6: /proc/efi/systab
|
||||
* Linux 2.6.7 and up: /sys/firmware/efi/systab
|
||||
@ -4960,9 +5489,7 @@ static int address_from_efi(off_t *address)
|
||||
|| strcmp(linebuf, "SMBIOS") == 0)
|
||||
{
|
||||
*address = strtoull(addrp, NULL, 0);
|
||||
if (!(opt.flags & FLAG_QUIET))
|
||||
printf("# %s entry point at 0x%08llx\n",
|
||||
linebuf, (unsigned long long)*address);
|
||||
eptype = linebuf;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
@ -4972,6 +5499,31 @@ static int address_from_efi(off_t *address)
|
||||
|
||||
if (ret == EFI_NO_SMBIOS)
|
||||
fprintf(stderr, "%s: SMBIOS entry point missing\n", filename);
|
||||
#elif defined(__FreeBSD__)
|
||||
/*
|
||||
* On FreeBSD, SMBIOS anchor base address in UEFI mode is exposed
|
||||
* via kernel environment:
|
||||
* https://svnweb.freebsd.org/base?view=revision&revision=307326
|
||||
*/
|
||||
ret = kenv(KENV_GET, "hint.smbios.0.mem", addrstr, sizeof(addrstr));
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
perror("kenv");
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
*address = strtoull(addrstr, NULL, 0);
|
||||
eptype = "SMBIOS";
|
||||
ret = 0;
|
||||
#else
|
||||
ret = EFI_NOT_FOUND;
|
||||
#endif
|
||||
|
||||
if (ret == 0 && !(opt.flags & FLAG_QUIET))
|
||||
printf("# %s entry point at 0x%08llx\n",
|
||||
eptype, (unsigned long long)*address);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -5000,6 +5552,7 @@ int main(int argc, char * const argv[])
|
||||
/* Set default option values */
|
||||
opt.devmem = DEFAULT_MEM_DEV;
|
||||
opt.flags = 0;
|
||||
opt.handle = ~0U;
|
||||
|
||||
if (parse_command_line(argc, argv)<0)
|
||||
{
|
||||
|
||||
477
dmioem.c
477
dmioem.c
@ -33,8 +33,11 @@
|
||||
enum DMI_VENDORS
|
||||
{
|
||||
VENDOR_UNKNOWN,
|
||||
VENDOR_HP,
|
||||
VENDOR_ACER,
|
||||
VENDOR_HP,
|
||||
VENDOR_HPE,
|
||||
VENDOR_IBM,
|
||||
VENDOR_LENOVO,
|
||||
};
|
||||
|
||||
static enum DMI_VENDORS dmi_vendor = VENDOR_UNKNOWN;
|
||||
@ -56,178 +59,16 @@ void dmi_set_vendor(const char *s)
|
||||
while (len && s[len - 1] == ' ')
|
||||
len--;
|
||||
|
||||
if (strncmp(s, "HP", len) == 0 || strncmp(s, "Hewlett-Packard", len) == 0)
|
||||
dmi_vendor = VENDOR_HP;
|
||||
else if (strncmp(s, "Acer", len) == 0)
|
||||
if (strncmp(s, "Acer", len) == 0)
|
||||
dmi_vendor = VENDOR_ACER;
|
||||
}
|
||||
|
||||
/*
|
||||
* HP-specific data structures are decoded here.
|
||||
*
|
||||
* Code contributed by John Cagle and Tyler Bell.
|
||||
*/
|
||||
|
||||
static void dmi_print_hp_net_iface_rec(u8 id, u8 bus, u8 dev, const u8 *mac)
|
||||
{
|
||||
/* Some systems do not provide an id. nic_ctr provides an artificial
|
||||
* id, and assumes the records will be provided "in order". Also,
|
||||
* using 0xFF marker is not future proof. 256 NICs is a lot, but
|
||||
* 640K ought to be enough for anybody(said no one, ever).
|
||||
* */
|
||||
static u8 nic_ctr;
|
||||
|
||||
if (id == 0xFF)
|
||||
id = ++nic_ctr;
|
||||
|
||||
if (dev == 0x00 && bus == 0x00)
|
||||
printf("\tNIC %d: Disabled\n", id);
|
||||
else if (dev == 0xFF && bus == 0xFF)
|
||||
printf("\tNIC %d: Not Installed\n", id);
|
||||
else
|
||||
{
|
||||
printf("\tNIC %d: PCI device %02x:%02x.%x, "
|
||||
"MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||
id, bus, dev >> 3, dev & 7,
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
}
|
||||
|
||||
static int dmi_decode_hp(const struct dmi_header *h)
|
||||
{
|
||||
u8 *data = h->data;
|
||||
int nic, ptr;
|
||||
u32 feat;
|
||||
|
||||
switch (h->type)
|
||||
{
|
||||
case 204:
|
||||
/*
|
||||
* Vendor Specific: HP ProLiant System/Rack Locator
|
||||
*/
|
||||
printf("HP ProLiant System/Rack Locator\n");
|
||||
if (h->length < 0x0B) break;
|
||||
printf("\tRack Name: %s\n", dmi_string(h, data[0x04]));
|
||||
printf("\tEnclosure Name: %s\n", dmi_string(h, data[0x05]));
|
||||
printf("\tEnclosure Model: %s\n", dmi_string(h, data[0x06]));
|
||||
printf("\tEnclosure Serial: %s\n", dmi_string(h, data[0x0A]));
|
||||
printf("\tEnclosure Bays: %d\n", data[0x08]);
|
||||
printf("\tServer Bay: %s\n", dmi_string(h, data[0x07]));
|
||||
printf("\tBays Filled: %d\n", data[0x09]);
|
||||
break;
|
||||
|
||||
case 209:
|
||||
case 221:
|
||||
/*
|
||||
* Vendor Specific: HP ProLiant NIC MAC Information
|
||||
*
|
||||
* This prints the BIOS NIC number,
|
||||
* PCI bus/device/function, and MAC address
|
||||
*
|
||||
* Type 209:
|
||||
* Offset | Name | Width | Description
|
||||
* -------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xD1, MAC Info
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | Dev No | BYTE | PCI Device/Function No
|
||||
* 0x05 | Bus No | BYTE | PCI Bus
|
||||
* 0x06 | MAC | 6B | MAC addr
|
||||
* 0x0C | NIC #2 | 8B | Repeat 0x04-0x0B
|
||||
*
|
||||
* Type 221: is deprecated in the latest docs
|
||||
*/
|
||||
printf(h->type == 221 ?
|
||||
"HP BIOS iSCSI NIC PCI and MAC Information\n" :
|
||||
"HP BIOS PXE NIC PCI and MAC Information\n");
|
||||
nic = 1;
|
||||
ptr = 4;
|
||||
while (h->length >= ptr + 8)
|
||||
{
|
||||
dmi_print_hp_net_iface_rec(nic,
|
||||
data[ptr + 0x01],
|
||||
data[ptr],
|
||||
&data[ptr + 0x02]);
|
||||
nic++;
|
||||
ptr += 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case 233:
|
||||
/*
|
||||
* Vendor Specific: HP ProLiant NIC MAC Information
|
||||
*
|
||||
* This prints the BIOS NIC number,
|
||||
* PCI bus/device/function, and MAC address
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* -------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xE9, NIC structure
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | Grp No | WORD | 0 for single segment
|
||||
* 0x06 | Bus No | BYTE | PCI Bus
|
||||
* 0x07 | Dev No | BYTE | PCI Device/Function No
|
||||
* 0x08 | MAC | 32B | MAC addr padded w/ 0s
|
||||
* 0x28 | Port No| BYTE | Each NIC maps to a Port
|
||||
*/
|
||||
printf("HP BIOS PXE NIC PCI and MAC Information\n");
|
||||
if (h->length < 0x0E) break;
|
||||
/* If the record isn't long enough, we don't have an ID
|
||||
* use 0xFF to use the internal counter.
|
||||
* */
|
||||
nic = h->length > 0x28 ? data[0x28] : 0xFF;
|
||||
dmi_print_hp_net_iface_rec(nic, data[0x06], data[0x07],
|
||||
&data[0x08]);
|
||||
break;
|
||||
|
||||
case 212:
|
||||
/*
|
||||
* Vendor Specific: HP 64-bit CRU Information
|
||||
*
|
||||
* Source: hpwdt kernel driver
|
||||
*/
|
||||
printf("HP 64-bit CRU Information\n");
|
||||
if (h->length < 0x18) break;
|
||||
printf("\tSignature: 0x%08x", DWORD(data + 0x04));
|
||||
if (is_printable(data + 0x04, 4))
|
||||
printf(" (%c%c%c%c)", data[0x04], data[0x05],
|
||||
data[0x06], data[0x07]);
|
||||
printf("\n");
|
||||
if (DWORD(data + 0x04) == 0x55524324)
|
||||
{
|
||||
u64 paddr = QWORD(data + 0x08);
|
||||
paddr.l += DWORD(data + 0x14);
|
||||
if (paddr.l < DWORD(data + 0x14))
|
||||
paddr.h++;
|
||||
printf("\tPhysical Address: 0x%08x%08x\n",
|
||||
paddr.h, paddr.l);
|
||||
printf("\tLength: 0x%08x\n", DWORD(data + 0x10));
|
||||
}
|
||||
break;
|
||||
|
||||
case 219:
|
||||
/*
|
||||
* Vendor Specific: HP ProLiant Information
|
||||
*
|
||||
* Source: hpwdt kernel driver
|
||||
*/
|
||||
printf("HP ProLiant Information\n");
|
||||
if (h->length < 0x08) break;
|
||||
printf("\tPower Features: 0x%08x\n", DWORD(data + 0x04));
|
||||
if (h->length < 0x0C) break;
|
||||
printf("\tOmega Features: 0x%08x\n", DWORD(data + 0x08));
|
||||
if (h->length < 0x14) break;
|
||||
feat = DWORD(data + 0x10);
|
||||
printf("\tMisc. Features: 0x%08x\n", feat);
|
||||
printf("\t\tiCRU: %s\n", feat & 0x0001 ? "Yes" : "No");
|
||||
printf("\t\tUEFI: %s\n", feat & 0x0408 ? "Yes" : "No");
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
else if (strncmp(s, "HP", len) == 0 || strncmp(s, "Hewlett-Packard", len) == 0)
|
||||
dmi_vendor = VENDOR_HP;
|
||||
else if (strncmp(s, "HPE", len) == 0 || strncmp(s, "Hewlett Packard Enterprise", len) == 0)
|
||||
dmi_vendor = VENDOR_HPE;
|
||||
else if (strncmp(s, "IBM", len) == 0)
|
||||
dmi_vendor = VENDOR_IBM;
|
||||
else if (strncmp(s, "LENOVO", len) == 0)
|
||||
dmi_vendor = VENDOR_LENOVO;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -272,6 +113,294 @@ static int dmi_decode_acer(const struct dmi_header *h)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* HPE-specific data structures are decoded here.
|
||||
*
|
||||
* Code contributed by John Cagle and Tyler Bell.
|
||||
*/
|
||||
|
||||
static void dmi_print_hp_net_iface_rec(u8 id, u8 bus, u8 dev, const u8 *mac)
|
||||
{
|
||||
/* Some systems do not provide an id. nic_ctr provides an artificial
|
||||
* id, and assumes the records will be provided "in order". Also,
|
||||
* using 0xFF marker is not future proof. 256 NICs is a lot, but
|
||||
* 640K ought to be enough for anybody(said no one, ever).
|
||||
* */
|
||||
static u8 nic_ctr;
|
||||
|
||||
if (id == 0xFF)
|
||||
id = ++nic_ctr;
|
||||
|
||||
if (dev == 0x00 && bus == 0x00)
|
||||
printf("\tNIC %d: Disabled\n", id);
|
||||
else if (dev == 0xFF && bus == 0xFF)
|
||||
printf("\tNIC %d: Not Installed\n", id);
|
||||
else
|
||||
{
|
||||
printf("\tNIC %d: PCI device %02x:%02x.%x, "
|
||||
"MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||
id, bus, dev >> 3, dev & 7,
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
}
|
||||
|
||||
static int dmi_decode_hp(const struct dmi_header *h)
|
||||
{
|
||||
u8 *data = h->data;
|
||||
int nic, ptr;
|
||||
u32 feat;
|
||||
const char *company = (dmi_vendor == VENDOR_HP) ? "HP" : "HPE";
|
||||
|
||||
switch (h->type)
|
||||
{
|
||||
case 204:
|
||||
/*
|
||||
* Vendor Specific: HPE ProLiant System/Rack Locator
|
||||
*/
|
||||
printf("%s ProLiant System/Rack Locator\n", company);
|
||||
if (h->length < 0x0B) break;
|
||||
printf("\tRack Name: %s\n", dmi_string(h, data[0x04]));
|
||||
printf("\tEnclosure Name: %s\n", dmi_string(h, data[0x05]));
|
||||
printf("\tEnclosure Model: %s\n", dmi_string(h, data[0x06]));
|
||||
printf("\tEnclosure Serial: %s\n", dmi_string(h, data[0x0A]));
|
||||
printf("\tEnclosure Bays: %d\n", data[0x08]);
|
||||
printf("\tServer Bay: %s\n", dmi_string(h, data[0x07]));
|
||||
printf("\tBays Filled: %d\n", data[0x09]);
|
||||
break;
|
||||
|
||||
case 209:
|
||||
case 221:
|
||||
/*
|
||||
* Vendor Specific: HPE ProLiant NIC MAC Information
|
||||
*
|
||||
* This prints the BIOS NIC number,
|
||||
* PCI bus/device/function, and MAC address
|
||||
*
|
||||
* Type 209:
|
||||
* Offset | Name | Width | Description
|
||||
* -------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xD1, MAC Info
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | Dev No | BYTE | PCI Device/Function No
|
||||
* 0x05 | Bus No | BYTE | PCI Bus
|
||||
* 0x06 | MAC | 6B | MAC addr
|
||||
* 0x0C | NIC #2 | 8B | Repeat 0x04-0x0B
|
||||
*
|
||||
* Type 221: is deprecated in the latest docs
|
||||
*/
|
||||
printf("%s %s\n", company,
|
||||
h->type == 221 ?
|
||||
"BIOS iSCSI NIC PCI and MAC Information" :
|
||||
"BIOS PXE NIC PCI and MAC Information");
|
||||
nic = 1;
|
||||
ptr = 4;
|
||||
while (h->length >= ptr + 8)
|
||||
{
|
||||
dmi_print_hp_net_iface_rec(nic,
|
||||
data[ptr + 0x01],
|
||||
data[ptr],
|
||||
&data[ptr + 0x02]);
|
||||
nic++;
|
||||
ptr += 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case 233:
|
||||
/*
|
||||
* Vendor Specific: HPE ProLiant NIC MAC Information
|
||||
*
|
||||
* This prints the BIOS NIC number,
|
||||
* PCI bus/device/function, and MAC address
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* -------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xE9, NIC structure
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | Grp No | WORD | 0 for single segment
|
||||
* 0x06 | Bus No | BYTE | PCI Bus
|
||||
* 0x07 | Dev No | BYTE | PCI Device/Function No
|
||||
* 0x08 | MAC | 32B | MAC addr padded w/ 0s
|
||||
* 0x28 | Port No| BYTE | Each NIC maps to a Port
|
||||
*/
|
||||
printf("%s BIOS PXE NIC PCI and MAC Information\n", company);
|
||||
if (h->length < 0x0E) break;
|
||||
/* If the record isn't long enough, we don't have an ID
|
||||
* use 0xFF to use the internal counter.
|
||||
* */
|
||||
nic = h->length > 0x28 ? data[0x28] : 0xFF;
|
||||
dmi_print_hp_net_iface_rec(nic, data[0x06], data[0x07],
|
||||
&data[0x08]);
|
||||
break;
|
||||
|
||||
case 212:
|
||||
/*
|
||||
* Vendor Specific: HPE 64-bit CRU Information
|
||||
*
|
||||
* Source: hpwdt kernel driver
|
||||
*/
|
||||
printf("%s 64-bit CRU Information\n", company);
|
||||
if (h->length < 0x18) break;
|
||||
printf("\tSignature: 0x%08x", DWORD(data + 0x04));
|
||||
if (is_printable(data + 0x04, 4))
|
||||
printf(" (%c%c%c%c)", data[0x04], data[0x05],
|
||||
data[0x06], data[0x07]);
|
||||
printf("\n");
|
||||
if (DWORD(data + 0x04) == 0x55524324)
|
||||
{
|
||||
u64 paddr = QWORD(data + 0x08);
|
||||
paddr.l += DWORD(data + 0x14);
|
||||
if (paddr.l < DWORD(data + 0x14))
|
||||
paddr.h++;
|
||||
printf("\tPhysical Address: 0x%08x%08x\n",
|
||||
paddr.h, paddr.l);
|
||||
printf("\tLength: 0x%08x\n", DWORD(data + 0x10));
|
||||
}
|
||||
break;
|
||||
|
||||
case 219:
|
||||
/*
|
||||
* Vendor Specific: HPE ProLiant Information
|
||||
*
|
||||
* Source: hpwdt kernel driver
|
||||
*/
|
||||
printf("%s ProLiant Information\n", company);
|
||||
if (h->length < 0x08) break;
|
||||
printf("\tPower Features: 0x%08x\n", DWORD(data + 0x04));
|
||||
if (h->length < 0x0C) break;
|
||||
printf("\tOmega Features: 0x%08x\n", DWORD(data + 0x08));
|
||||
if (h->length < 0x14) break;
|
||||
feat = DWORD(data + 0x10);
|
||||
printf("\tMisc. Features: 0x%08x\n", feat);
|
||||
printf("\t\tiCRU: %s\n", feat & 0x0001 ? "Yes" : "No");
|
||||
printf("\t\tUEFI: %s\n", feat & 0x1400 ? "Yes" : "No");
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dmi_decode_ibm_lenovo(const struct dmi_header *h)
|
||||
{
|
||||
u8 *data = h->data;
|
||||
|
||||
switch (h->type)
|
||||
{
|
||||
case 131:
|
||||
/*
|
||||
* Vendor Specific: ThinkVantage Technologies feature bits
|
||||
*
|
||||
* Source: Compal hel81 Service Manual Software Specification,
|
||||
* documented under "System Management BIOS(SM BIOS)
|
||||
* version 2.4 or greater"
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* ----------------------------------------------
|
||||
* 0x00 | Type | BYTE | 0x83
|
||||
* 0x01 | Length | BYTE | 0x16
|
||||
* 0x02 | Handle | WORD | Varies
|
||||
* 0x04 | Version | BYTE | 0x01
|
||||
* 0x05 | TVT Structure | BYTEx16 | Each of the 128 bits represents a TVT feature:
|
||||
* | | | - bit 127 means diagnostics (PC Doctor) is available
|
||||
* | | | (http://www.pc-doctor.com/company/pr-articles/45-lenovo-introduces-thinkvantage-toolbox)
|
||||
* | | | - the rest (126-0) are reserved/unknown
|
||||
*
|
||||
* It must also be followed by a string containing
|
||||
* "TVT-Enablement". There exist other type 131 records
|
||||
* with different length and a different string, for
|
||||
* other purposes.
|
||||
*/
|
||||
|
||||
if (h->length != 0x16
|
||||
|| strcmp(dmi_string(h, 1), "TVT-Enablement") != 0)
|
||||
return 0;
|
||||
|
||||
printf("ThinkVantage Technologies\n");
|
||||
printf("\tVersion: %u\n", data[0x04]);
|
||||
printf("\tDiagnostics: %s\n",
|
||||
data[0x14] & 0x80 ? "Available" : "No");
|
||||
break;
|
||||
|
||||
case 135:
|
||||
/*
|
||||
* Vendor Specific: Device Presence Detection bits
|
||||
*
|
||||
* Source: Compal hel81 Service Manual Software Specification,
|
||||
* documented as "SMBIOS Type 135: Bulk for Lenovo
|
||||
* Mobile PC Unique OEM Data" under appendix D.
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* ---------------------------------------------------
|
||||
* 0x00 | Type | BYTE | 0x87
|
||||
* 0x01 | Length | BYTE | 0x0A
|
||||
* 0x02 | Handle | WORD | Varies
|
||||
* 0x04 | Signature | WORD | 0x5054 (ASCII for "TP")
|
||||
* 0x06 | OEM struct offset | BYTE | 0x07
|
||||
* 0x07 | OEM struct number | BYTE | 0x03, for this structure
|
||||
* 0x08 | OEM struct revision | BYTE | 0x01, for this format
|
||||
* 0x09 | Device presence bits | BYTE | Each of the 8 bits indicates device presence:
|
||||
* | | | - bit 0 indicates the presence of a fingerprint reader
|
||||
* | | | - the rest (7-1) are reserved/unknown
|
||||
*
|
||||
* Other OEM struct number+rev combinations have been
|
||||
* seen in the wild but we don't know how to decode
|
||||
* them.
|
||||
*/
|
||||
|
||||
if (h->length < 0x0A || data[0x04] != 'T' || data[0x05] != 'P')
|
||||
return 0;
|
||||
|
||||
/* Bail out if not the expected format */
|
||||
if (data[0x06] != 0x07 || data[0x07] != 0x03 || data[0x08] != 0x01)
|
||||
return 0;
|
||||
|
||||
printf("ThinkPad Device Presence Detection\n");
|
||||
printf("\tFingerprint Reader: %s\n",
|
||||
data[0x09] & 0x01 ? "Present" : "No");
|
||||
break;
|
||||
|
||||
case 140:
|
||||
/*
|
||||
* Vendor Specific: ThinkPad Embedded Controller Program
|
||||
*
|
||||
* Source: some guesswork, and publicly available information;
|
||||
* Lenovo's BIOS update READMEs often contain the ECP IDs
|
||||
* which match the first string in this type.
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* ----------------------------------------------------
|
||||
* 0x00 | Type | BYTE | 0x8C
|
||||
* 0x01 | Length | BYTE |
|
||||
* 0x02 | Handle | WORD | Varies
|
||||
* 0x04 | Signature | BYTEx6 | ASCII for "LENOVO"
|
||||
* 0x0A | OEM struct offset | BYTE | 0x0B
|
||||
* 0x0B | OEM struct number | BYTE | 0x07, for this structure
|
||||
* 0x0C | OEM struct revision | BYTE | 0x01, for this format
|
||||
* 0x0D | ECP version ID | STRING |
|
||||
* 0x0E | ECP release date | STRING |
|
||||
*/
|
||||
|
||||
if (h->length < 0x0F || memcmp(data + 4, "LENOVO", 6) != 0)
|
||||
return 0;
|
||||
|
||||
/* Bail out if not the expected format */
|
||||
if (data[0x0A] != 0x0B || data[0x0B] != 0x07 || data[0x0C] != 0x01)
|
||||
return 0;
|
||||
|
||||
printf("ThinkPad Embedded Controller Program\n");
|
||||
printf("\tVersion ID: %s\n", dmi_string(h, 1));
|
||||
printf("\tRelease Date: %s\n", dmi_string(h, 2));
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch vendor-specific entries decoding
|
||||
* Return 1 if decoding was successful, 0 otherwise
|
||||
@ -281,9 +410,13 @@ int dmi_decode_oem(const struct dmi_header *h)
|
||||
switch (dmi_vendor)
|
||||
{
|
||||
case VENDOR_HP:
|
||||
case VENDOR_HPE:
|
||||
return dmi_decode_hp(h);
|
||||
case VENDOR_ACER:
|
||||
return dmi_decode_acer(h);
|
||||
case VENDOR_IBM:
|
||||
case VENDOR_LENOVO:
|
||||
return dmi_decode_ibm_lenovo(h);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
31
dmiopt.c
31
dmiopt.c
@ -113,7 +113,7 @@ static u8 *parse_opt_type(u8 *p, const char *arg)
|
||||
char *next;
|
||||
|
||||
val = strtoul(arg, &next, 0);
|
||||
if (next == arg)
|
||||
if (next == arg || (*next != '\0' && *next != ',' && *next != ' '))
|
||||
{
|
||||
fprintf(stderr, "Invalid type keyword: %s\n", arg);
|
||||
print_opt_type_list();
|
||||
@ -156,6 +156,7 @@ static const struct string_keyword opt_string_keyword[] = {
|
||||
{ "system-version", 1, 0x06 },
|
||||
{ "system-serial-number", 1, 0x07 },
|
||||
{ "system-uuid", 1, 0x08 }, /* dmi_system_uuid() */
|
||||
{ "system-family", 1, 0x1a },
|
||||
{ "baseboard-manufacturer", 2, 0x04 },
|
||||
{ "baseboard-product-name", 2, 0x05 },
|
||||
{ "baseboard-version", 2, 0x06 },
|
||||
@ -227,7 +228,7 @@ static int parse_opt_oem_string(const char *arg)
|
||||
goto done;
|
||||
|
||||
val = strtoul(arg, &next, 10);
|
||||
if (next == arg || val == 0x00 || val > 0xff)
|
||||
if (next == arg || *next != '\0' || val == 0x00 || val > 0xff)
|
||||
{
|
||||
fprintf(stderr, "Invalid OEM string number: %s\n", arg);
|
||||
return -1;
|
||||
@ -239,6 +240,19 @@ done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 parse_opt_handle(const char *arg)
|
||||
{
|
||||
u32 val;
|
||||
char *next;
|
||||
|
||||
val = strtoul(arg, &next, 0);
|
||||
if (next == arg || *next != '\0' || val > 0xffff)
|
||||
{
|
||||
fprintf(stderr, "Invalid handle number: %s\n", arg);
|
||||
return ~0;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Command line options handling
|
||||
@ -248,7 +262,7 @@ done:
|
||||
int parse_command_line(int argc, char * const argv[])
|
||||
{
|
||||
int option;
|
||||
const char *optstring = "d:hqs:t:uV";
|
||||
const char *optstring = "d:hqs:t:uH:V";
|
||||
struct option longopts[] = {
|
||||
{ "dev-mem", required_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
@ -258,6 +272,7 @@ int parse_command_line(int argc, char * const argv[])
|
||||
{ "dump", no_argument, NULL, 'u' },
|
||||
{ "dump-bin", required_argument, NULL, 'B' },
|
||||
{ "from-dump", required_argument, NULL, 'F' },
|
||||
{ "handle", required_argument, NULL, 'H' },
|
||||
{ "oem-string", required_argument, NULL, 'O' },
|
||||
{ "no-sysfs", no_argument, NULL, 'S' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
@ -299,6 +314,11 @@ int parse_command_line(int argc, char * const argv[])
|
||||
if (opt.type == NULL)
|
||||
return -1;
|
||||
break;
|
||||
case 'H':
|
||||
opt.handle = parse_opt_handle(optarg);
|
||||
if (opt.handle == ~0U)
|
||||
return -1;
|
||||
break;
|
||||
case 'u':
|
||||
opt.flags |= FLAG_DUMP;
|
||||
break;
|
||||
@ -325,9 +345,9 @@ int parse_command_line(int argc, char * const argv[])
|
||||
|
||||
/* Check for mutually exclusive output format options */
|
||||
if ((opt.string != NULL) + (opt.type != NULL)
|
||||
+ !!(opt.flags & FLAG_DUMP_BIN) > 1)
|
||||
+ !!(opt.flags & FLAG_DUMP_BIN) + (opt.handle != ~0U) > 1)
|
||||
{
|
||||
fprintf(stderr, "Options --string, --type and --dump-bin are mutually exclusive\n");
|
||||
fprintf(stderr, "Options --string, --type, --handle and --dump-bin are mutually exclusive\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -350,6 +370,7 @@ void print_help(void)
|
||||
" -q, --quiet Less verbose output\n"
|
||||
" -s, --string KEYWORD Only display the value of the given DMI string\n"
|
||||
" -t, --type TYPE Only display the entries of given type\n"
|
||||
" -H, --handle HANDLE Only display the entry of given handle\n"
|
||||
" -u, --dump Do not decode the entries\n"
|
||||
" --dump-bin FILE Dump the DMI data to a binary file\n"
|
||||
" --from-dump FILE Read the DMI data from a binary file\n"
|
||||
|
||||
1
dmiopt.h
1
dmiopt.h
@ -35,6 +35,7 @@ struct opt
|
||||
u8 *type;
|
||||
const struct string_keyword *string;
|
||||
char *dumpfile;
|
||||
u32 handle;
|
||||
};
|
||||
extern struct opt opt;
|
||||
|
||||
|
||||
@ -60,6 +60,9 @@ program.
|
||||
.BR "-d" ", " "--dev-mem FILE"
|
||||
Read memory from device \fBFILE\fR (default: \fB/dev/mem\fR)
|
||||
.TP
|
||||
.BR " " " " "--pir full"
|
||||
Decode the details of the PCI IRQ routing table
|
||||
.TP
|
||||
.BR "-h" ", " "--help"
|
||||
Display usage information and exit
|
||||
.TP
|
||||
|
||||
@ -74,7 +74,7 @@ Only display the value of the \s-1DMI\s0 string identified by \fBKEYWORD\fR.
|
||||
\fBbios-version\fR, \fBbios-release-date\fR,
|
||||
\fBsystem-manufacturer\fR, \fBsystem-product-name\fR,
|
||||
\fBsystem-version\fR, \fBsystem-serial-number\fR,
|
||||
\fBsystem-uuid\fR,
|
||||
\fBsystem-uuid\fR, \fBsystem-family\fR,
|
||||
\fBbaseboard-manufacturer\fR, \fBbaseboard-product-name\fR,
|
||||
\fBbaseboard-version\fR, \fBbaseboard-serial-number\fR,
|
||||
\fBbaseboard-asset-tag\fR, \fBchassis-manufacturer\fR,
|
||||
@ -115,6 +115,10 @@ is printed and
|
||||
.B dmidecode
|
||||
exits with an error.
|
||||
.TP
|
||||
.BR "-H" ", " "--handle HANDLE"
|
||||
Only display the entry whose handle matches \fBHANDLE\fR. \fBHANDLE\fR
|
||||
is a 16-bit integer.
|
||||
.TP
|
||||
.BR "-u" ", " "--dump"
|
||||
Do not decode the entries, dump their contents as hexadecimal instead.
|
||||
Note that this is still a text output, no binary data will be thrown upon
|
||||
|
||||
27
types.h
27
types.h
@ -11,8 +11,7 @@ typedef unsigned int u32;
|
||||
/*
|
||||
* You may use the following defines to adjust the type definitions
|
||||
* depending on the architecture:
|
||||
* - Define BIGENDIAN on big-endian systems. Untested, as all target
|
||||
* systems to date are little-endian.
|
||||
* - Define BIGENDIAN on big-endian systems.
|
||||
* - Define ALIGNMENT_WORKAROUND if your system doesn't support
|
||||
* non-aligned memory access. In this case, we use a slower, but safer,
|
||||
* memory access method. This should be done automatically in config.h
|
||||
@ -31,7 +30,7 @@ typedef struct {
|
||||
} u64;
|
||||
#endif
|
||||
|
||||
#ifdef ALIGNMENT_WORKAROUND
|
||||
#if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN)
|
||||
static inline u64 U64(u32 low, u32 high)
|
||||
{
|
||||
u64 self;
|
||||
@ -43,20 +42,18 @@ static inline u64 U64(u32 low, u32 high)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ALIGNMENT_WORKAROUND
|
||||
# ifdef BIGENDIAN
|
||||
# define WORD(x) (u16)((x)[1] + ((x)[0] << 8))
|
||||
# define DWORD(x) (u32)((x)[3] + ((x)[2] << 8) + ((x)[1] << 16) + ((x)[0] << 24))
|
||||
# define QWORD(x) (U64(DWORD(x + 4), DWORD(x)))
|
||||
# else /* BIGENDIAN */
|
||||
# define WORD(x) (u16)((x)[0] + ((x)[1] << 8))
|
||||
# define DWORD(x) (u32)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24))
|
||||
# define QWORD(x) (U64(DWORD(x), DWORD(x + 4)))
|
||||
# endif /* BIGENDIAN */
|
||||
#else /* ALIGNMENT_WORKAROUND */
|
||||
/*
|
||||
* Per SMBIOS v2.8.0 and later, all structures assume a little-endian
|
||||
* ordering convention.
|
||||
*/
|
||||
#if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN)
|
||||
#define WORD(x) (u16)((x)[0] + ((x)[1] << 8))
|
||||
#define DWORD(x) (u32)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24))
|
||||
#define QWORD(x) (U64(DWORD(x), DWORD(x + 4)))
|
||||
#else /* ALIGNMENT_WORKAROUND || BIGENDIAN */
|
||||
#define WORD(x) (u16)(*(const u16 *)(x))
|
||||
#define DWORD(x) (u32)(*(const u32 *)(x))
|
||||
#define QWORD(x) (*(const u64 *)(x))
|
||||
#endif /* ALIGNMENT_WORKAROUND */
|
||||
#endif /* ALIGNMENT_WORKAROUND || BIGENDIAN */
|
||||
|
||||
#endif
|
||||
|
||||
60
util.c
60
util.c
@ -2,7 +2,7 @@
|
||||
* Common "util" functions
|
||||
* This file is part of the dmidecode project.
|
||||
*
|
||||
* Copyright (C) 2002-2017 Jean Delvare <jdelvare@suse.de>
|
||||
* Copyright (C) 2002-2018 Jean Delvare <jdelvare@suse.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -59,7 +59,6 @@ static int myread(int fd, u8 *buf, size_t count, const char *prefix)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
close(fd);
|
||||
perror(prefix);
|
||||
return -1;
|
||||
}
|
||||
@ -70,7 +69,6 @@ static int myread(int fd, u8 *buf, size_t count, const char *prefix)
|
||||
|
||||
if (r2 != count)
|
||||
{
|
||||
close(fd);
|
||||
fprintf(stderr, "%s: Unexpected end of file\n", prefix);
|
||||
return -1;
|
||||
}
|
||||
@ -90,19 +88,17 @@ int checksum(const u8 *buf, size_t len)
|
||||
|
||||
/*
|
||||
* Reads all of file from given offset, up to max_len bytes.
|
||||
* A buffer of max_len bytes is allocated by this function, and
|
||||
* A buffer of at most max_len bytes is allocated by this function, and
|
||||
* needs to be freed by the caller.
|
||||
* This provides a similar usage model to mem_chunk()
|
||||
*
|
||||
* Returns pointer to buffer of max_len bytes, or NULL on error, and
|
||||
* Returns a pointer to the allocated buffer, or NULL on error, and
|
||||
* sets max_len to the length actually read.
|
||||
*
|
||||
*/
|
||||
void *read_file(off_t base, size_t *max_len, const char *filename)
|
||||
{
|
||||
struct stat statbuf;
|
||||
int fd;
|
||||
size_t r2 = 0;
|
||||
ssize_t r;
|
||||
u8 *p;
|
||||
|
||||
/*
|
||||
@ -116,12 +112,20 @@ void *read_file(off_t base, size_t *max_len, const char *filename)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (lseek(fd, base, SEEK_SET) == -1)
|
||||
/*
|
||||
* Check file size, don't allocate more than can be read.
|
||||
*/
|
||||
if (fstat(fd, &statbuf) == 0)
|
||||
{
|
||||
fprintf(stderr, "%s: ", filename);
|
||||
perror("lseek");
|
||||
p = NULL;
|
||||
goto out;
|
||||
if (base >= statbuf.st_size)
|
||||
{
|
||||
fprintf(stderr, "%s: Can't read data beyond EOF\n",
|
||||
filename);
|
||||
p = NULL;
|
||||
goto out;
|
||||
}
|
||||
if (*max_len > (size_t)statbuf.st_size - base)
|
||||
*max_len = statbuf.st_size - base;
|
||||
}
|
||||
|
||||
if ((p = malloc(*max_len)) == NULL)
|
||||
@ -130,27 +134,23 @@ void *read_file(off_t base, size_t *max_len, const char *filename)
|
||||
goto out;
|
||||
}
|
||||
|
||||
do
|
||||
if (lseek(fd, base, SEEK_SET) == -1)
|
||||
{
|
||||
r = read(fd, p + r2, *max_len - r2);
|
||||
if (r == -1)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
perror(filename);
|
||||
free(p);
|
||||
p = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
r2 += r;
|
||||
fprintf(stderr, "%s: ", filename);
|
||||
perror("lseek");
|
||||
goto err_free;
|
||||
}
|
||||
while (r != 0);
|
||||
|
||||
*max_len = r2;
|
||||
if (myread(fd, p, *max_len, filename) == 0)
|
||||
goto out;
|
||||
|
||||
err_free:
|
||||
free(p);
|
||||
p = NULL;
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
if (close(fd) == -1)
|
||||
perror(filename);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user