mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 02:40:08 +00:00
parent
1e379cb3a9
commit
fe426e6f8f
74
repos/os/run/smbios_decoder.run
Normal file
74
repos/os/run/smbios_decoder.run
Normal file
@ -0,0 +1,74 @@
|
||||
assert_spec x86_64
|
||||
|
||||
if { "[board]" ne "pc" || [expr ![have_spec nova] && ![have_spec hw]] } {
|
||||
puts "Run script is only supported on hw/pc and nova/pc"
|
||||
exit 0
|
||||
}
|
||||
|
||||
set build_components { app/smbios_decoder core init timer server/report_rom }
|
||||
|
||||
source ${genode_dir}/repos/base/run/platform_drv.inc
|
||||
|
||||
append_platform_drv_build_components
|
||||
|
||||
build $build_components
|
||||
|
||||
create_boot_directory
|
||||
|
||||
append config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="CPU"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<service name="Report"> <child name="report_rom"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<default caps="200"/>}
|
||||
|
||||
append_platform_drv_config
|
||||
|
||||
append config {
|
||||
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides>
|
||||
<service name="Report"/>
|
||||
<service name="ROM"/>
|
||||
</provides>
|
||||
<config verbose="yes"/>
|
||||
</start>
|
||||
|
||||
<start name="smbios_decoder">
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<route>
|
||||
<service name="Report"> <child name="report_rom"/> </service>
|
||||
<service name="ROM" label="smbios_table"> <child name="acpi_report_rom"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>
|
||||
}
|
||||
|
||||
install_config $config
|
||||
|
||||
set boot_modules {
|
||||
report_rom
|
||||
core init ld.lib.so
|
||||
smbios_decoder
|
||||
}
|
||||
|
||||
append_platform_drv_boot_modules
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -nographic"
|
||||
|
||||
run_genode_until "report_rom] <structure type=\"0\" .*?description=\"BIOS Information\">.*?report_rom] </result>.*?\n" 20
|
789
repos/os/src/app/smbios_decoder/main.cc
Normal file
789
repos/os/src/app/smbios_decoder/main.cc
Normal file
@ -0,0 +1,789 @@
|
||||
/*
|
||||
* \brief Decode information from SMBIOS table and report it as XML
|
||||
* \author Martin Stein
|
||||
* \date 2019-07-04
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/smbios.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <os/reporter.h>
|
||||
#include <base/component.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
class Table
|
||||
{
|
||||
private:
|
||||
|
||||
/* two 0..255 numbers, 1 dot, terminating null*/
|
||||
using Version_2_string = String<3 * 2 + 1 + 1>;
|
||||
|
||||
/* address value in hex. 2 chars prefix, terminating null */
|
||||
using Addr_string = String<sizeof(addr_t) * 2 + 2 + 1>;
|
||||
|
||||
/* 64bit value, 2 char unit, terminating null */
|
||||
using Size_string = String<20 + 2 + 1>;
|
||||
|
||||
/* 16 two-digit hex values, 4 hyphen, terminating null */
|
||||
using Uuid_string = String<2 * 16 + 4 + 1>;
|
||||
|
||||
/* 2 digit hex value with padding but w/o prefix */
|
||||
struct Uuid_hex : Hex
|
||||
{
|
||||
Uuid_hex(char digit) : Hex(digit, Hex::OMIT_PREFIX, Hex::PAD) { }
|
||||
};
|
||||
|
||||
addr_t const _base;
|
||||
addr_t const _end;
|
||||
addr_t const _verbose;
|
||||
uint8_t _version_major { (uint8_t)~0 };
|
||||
uint8_t _version_minor { (uint8_t)~0 };
|
||||
|
||||
void _warn(char const *msg) const;
|
||||
|
||||
const char *_string_set_item(Smbios_structure const &header,
|
||||
uint8_t idx) const;
|
||||
|
||||
char const *_bios_character_0(uint8_t idx) const;
|
||||
|
||||
char const *_system_wake_up_type(uint8_t idx) const;
|
||||
|
||||
const char *_base_board_type(uint8_t idx) const;
|
||||
|
||||
char const *_base_board_feature(uint8_t idx) const;
|
||||
|
||||
void _report_base_board_features(Reporter::Xml_generator &xml,
|
||||
uint8_t code) const;
|
||||
|
||||
void _report_base_board_handles(Reporter::Xml_generator &xml,
|
||||
uint8_t count,
|
||||
uint8_t const *data) const;
|
||||
|
||||
void _report_base_board(Reporter::Xml_generator &xml,
|
||||
Smbios_structure const &header) const;
|
||||
|
||||
void _report_bios_character_0(Reporter::Xml_generator &xml,
|
||||
uint64_t code) const;
|
||||
|
||||
char const *_bios_character_1(uint8_t idx) const;
|
||||
|
||||
void _report_bios_character_1(Reporter::Xml_generator &xml,
|
||||
uint8_t code) const;
|
||||
|
||||
char const *_bios_character_2(uint8_t idx) const;
|
||||
|
||||
void _report_bios_character_2(Reporter::Xml_generator &xml,
|
||||
uint8_t code) const;
|
||||
|
||||
void _report_bios_rom_size(Reporter::Xml_generator &xml,
|
||||
uint8_t code_1,
|
||||
uint16_t code_2) const;
|
||||
|
||||
void _report_string(Reporter::Xml_generator &xml,
|
||||
char const *type,
|
||||
char const *value) const;
|
||||
|
||||
void _report_string_set_item(Reporter::Xml_generator &xml,
|
||||
Smbios_structure const &header,
|
||||
char const *type,
|
||||
unsigned idx) const;
|
||||
|
||||
void _report_system_uuid(Reporter::Xml_generator &xml,
|
||||
uint8_t const *data) const;
|
||||
|
||||
void _report_system(Reporter::Xml_generator &xml,
|
||||
Smbios_structure const &header) const;
|
||||
|
||||
void _report_bios(Reporter::Xml_generator &xml,
|
||||
Smbios_structure const &header) const;
|
||||
|
||||
void _report_smbios_struct(Reporter::Xml_generator &xml,
|
||||
Smbios_structure const &smbios_struct) const;
|
||||
|
||||
void _report_smbios_structs(Reporter::Xml_generator &xml,
|
||||
Dmi_entry_point const &smbios_ep) const;
|
||||
|
||||
void _report_dmi_ep(Reporter::Xml_generator &xml,
|
||||
Dmi_entry_point const &ep) const;
|
||||
|
||||
void _report_smbios_ep(Reporter::Xml_generator &xml,
|
||||
Smbios_entry_point const &smbios_ep) const;
|
||||
|
||||
public:
|
||||
|
||||
Table(addr_t base,
|
||||
size_t size,
|
||||
bool verbose)
|
||||
:
|
||||
_base { base },
|
||||
_end { base + size },
|
||||
_verbose { verbose }
|
||||
{ }
|
||||
|
||||
void report(Reporter::Xml_generator &xml) const;
|
||||
};
|
||||
|
||||
|
||||
class Main
|
||||
{
|
||||
private:
|
||||
|
||||
Env &_env;
|
||||
Attached_rom_dataspace _config_ds { _env, "config" };
|
||||
Xml_node _config { _config_ds.xml() };
|
||||
bool const _verbose { _config.attribute_value("verbose", false) };
|
||||
Expanding_reporter _reporter { _env, "result", "result" };
|
||||
Attached_rom_dataspace _table_ds { _env, "smbios_table" };
|
||||
Signal_handler<Main> _table_ds_sigh { _env.ep(), *this, &Main::_handle_table_ds };
|
||||
Constructible<Table> _table { };
|
||||
|
||||
void _handle_table_ds();
|
||||
|
||||
public:
|
||||
|
||||
Main(Env &env);
|
||||
};
|
||||
|
||||
|
||||
/***************
|
||||
** Component **
|
||||
***************/
|
||||
|
||||
void Component::construct(Genode::Env &env)
|
||||
{
|
||||
static Main main { env };
|
||||
}
|
||||
|
||||
|
||||
/**********
|
||||
** Main **
|
||||
**********/
|
||||
|
||||
Main::Main(Env &env) : _env { env }
|
||||
{
|
||||
_table_ds.sigh(_table_ds_sigh);
|
||||
_handle_table_ds();
|
||||
}
|
||||
|
||||
|
||||
void Main::_handle_table_ds()
|
||||
{
|
||||
_table_ds.update();
|
||||
if (!_table_ds.valid()) {
|
||||
return;
|
||||
}
|
||||
_table.construct((addr_t)_table_ds.local_addr<int>(), _table_ds.size(), _verbose);
|
||||
_reporter.generate([&] (Reporter::Xml_generator &xml) {
|
||||
_table->report(xml);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/***********
|
||||
** Table **
|
||||
***********/
|
||||
|
||||
void Table::_report_string(Reporter::Xml_generator &xml,
|
||||
char const *type,
|
||||
char const *value) const
|
||||
{
|
||||
xml.node(type, [&] () { xml.attribute("value", value); });
|
||||
}
|
||||
|
||||
|
||||
const char *Table::_string_set_item(Smbios_structure const &header,
|
||||
uint8_t idx) const
|
||||
{
|
||||
if (idx == 0) {
|
||||
return "[not specified]";
|
||||
}
|
||||
uint8_t const *data { (uint8_t *)&header };
|
||||
char const *result = (char *)data + header.length;
|
||||
while (idx > 1 && *result) {
|
||||
result += strlen(result);
|
||||
result++;
|
||||
idx--;
|
||||
}
|
||||
if (!*result) {
|
||||
return "[bad index]";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void Table::_warn(char const *msg) const
|
||||
{
|
||||
if (!_verbose) {
|
||||
return;
|
||||
}
|
||||
warning(msg);
|
||||
}
|
||||
|
||||
|
||||
char const *Table::_system_wake_up_type(uint8_t idx) const
|
||||
{
|
||||
switch (idx) {
|
||||
case 0: return "Reserved";
|
||||
case 1: return "Other";
|
||||
case 2: return "Unknown";
|
||||
case 3: return "APM Timer";
|
||||
case 4: return "Modem Ring";
|
||||
case 5: return "LAN Remote";
|
||||
case 6: return "Power Switch";
|
||||
case 7: return "PCI PME#";
|
||||
case 8: return "AC Power Restored";
|
||||
default: return "[out of spec]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char const *Table::_bios_character_0(uint8_t idx) const
|
||||
{
|
||||
switch (idx) {
|
||||
case 4: return "ISA is supported";
|
||||
case 5: return "MCA is supported";
|
||||
case 6: return "EISA is supported";
|
||||
case 7: return "PCI is supported";
|
||||
case 8: return "PC Card (PCMCIA) is supported";
|
||||
case 9: return "PNP is supported";
|
||||
case 10: return "APM is supported";
|
||||
case 11: return "BIOS is upgradeable";
|
||||
case 12: return "BIOS shadowing is allowed";
|
||||
case 13: return "VLB is supported";
|
||||
case 14: return "ESCD support is available";
|
||||
case 15: return "Boot from CD is supported";
|
||||
case 16: return "Selectable boot is supported";
|
||||
case 17: return "BIOS ROM is socketed";
|
||||
case 18: return "Boot from PC Card (PCMCIA) is supported";
|
||||
case 19: return "EDD is supported";
|
||||
case 20: return "Japanese floppy for NEC 9800 1.2 MB is supported (int 13h)";
|
||||
case 21: return "Japanese floppy for Toshiba 1.2 MB is supported (int 13h)";
|
||||
case 22: return "5.25"/360 kB floppy services are supported (int 13h)";
|
||||
case 23: return "5.25"/1.2 MB floppy services are supported (int 13h)";
|
||||
case 24: return "3.5"/720 kB floppy services are supported (int 13h)";
|
||||
case 25: return "3.5"/2.88 MB floppy services are supported (int 13h)";
|
||||
case 26: return "Print screen service is supported (int 5h)";
|
||||
case 27: return "8042 keyboard services are supported (int 9h)";
|
||||
case 28: return "Serial services are supported (int 14h)";
|
||||
case 29: return "Printer services are supported (int 17h)";
|
||||
case 30: return "CGA/mono video services are supported (int 10h)";
|
||||
case 31: return "NEC PC-98";
|
||||
default: return "[bad index]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char const *Table::_bios_character_1(uint8_t idx) const
|
||||
{
|
||||
switch (idx) {
|
||||
case 0: return "ACPI is supported";
|
||||
case 1: return "USB legacy is supported";
|
||||
case 2: return "AGP is supported";
|
||||
case 3: return "I2O boot is supported";
|
||||
case 4: return "LS-120 boot is supported";
|
||||
case 5: return "ATAPI Zip drive boot is supported";
|
||||
case 6: return "IEEE 1394 boot is supported";
|
||||
case 7: return "Smart battery is supported";
|
||||
default: return "[bad index]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char const *Table::_bios_character_2(uint8_t idx) const
|
||||
{
|
||||
switch (idx) {
|
||||
case 0: return "BIOS boot specification is supported";
|
||||
case 1: return "Function key-initiated network boot is supported";
|
||||
case 2: return "Targeted content distribution is supported";
|
||||
case 3: return "UEFI is supported";
|
||||
case 4: return "System is a virtual machine";
|
||||
default: return "[bad index]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char const *Table::_base_board_feature(uint8_t idx) const
|
||||
{
|
||||
switch (idx) {
|
||||
case 0: return "Board is a hosting board";
|
||||
case 1: return "Board requires at least one daughter board";
|
||||
case 2: return "Board is removable";
|
||||
case 3: return "Board is replaceable";
|
||||
case 4: return "Board is hot swappable";
|
||||
default: return "[bad index]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_base_board_features(Reporter::Xml_generator &xml,
|
||||
uint8_t code) const
|
||||
{
|
||||
if ((code & 0x1f) == 0) {
|
||||
_report_string(xml, "feature", "[none]");
|
||||
return;
|
||||
}
|
||||
for (uint8_t idx = 0; idx < 5; idx++) {
|
||||
if (code & (1 << idx)) {
|
||||
_report_string(xml, "feature", _base_board_feature(idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_bios_character_0(Reporter::Xml_generator &xml,
|
||||
uint64_t code) const
|
||||
{
|
||||
if (code & (1 << 3)) {
|
||||
xml.node("characteristic", [&] () {
|
||||
xml.attribute("value", "BIOS characteristics not supported");
|
||||
});
|
||||
return;
|
||||
}
|
||||
for (uint8_t idx = 4; idx <= 31; idx++) {
|
||||
if ((code & (1 << idx)) == 0) {
|
||||
continue;
|
||||
}
|
||||
xml.node("characteristic", [&] () {
|
||||
xml.attribute("value", _bios_character_0(idx));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_bios_character_1(Reporter::Xml_generator &xml,
|
||||
uint8_t code) const
|
||||
{
|
||||
for (uint8_t idx = 0; idx <= 7; idx++) {
|
||||
if ((code & (1 << idx)) == 0) {
|
||||
continue;
|
||||
}
|
||||
xml.node("characteristic", [&] () {
|
||||
xml.attribute("value", _bios_character_1(idx));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_bios_character_2(Reporter::Xml_generator &xml,
|
||||
uint8_t code) const
|
||||
{
|
||||
for (uint8_t idx = 0; idx <= 4; idx++) {
|
||||
if ((code & (1 << idx)) == 0) {
|
||||
continue;
|
||||
}
|
||||
xml.node("characteristic", [&] () {
|
||||
xml.attribute("value", _bios_character_2(idx));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_bios_rom_size(Reporter::Xml_generator &xml,
|
||||
uint8_t code_1,
|
||||
uint16_t code_2) const
|
||||
{
|
||||
xml.node("rom-size", [&] () {
|
||||
if (code_1 != 0xff) {
|
||||
xml.attribute("value", Size_string(((size_t)code_1 + 1) << 6, " KB"));
|
||||
return;
|
||||
}
|
||||
switch (code_2 >> 14) {
|
||||
case 0: xml.attribute("value", Size_string(code_2 & 0x3fff, " MB")); return;
|
||||
case 1: xml.attribute("value", Size_string(code_2 & 0x3fff, " GB")); return;
|
||||
default: xml.attribute("value", "[bad unit]"); return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_string_set_item(Reporter::Xml_generator &xml,
|
||||
Smbios_structure const &header,
|
||||
char const *type,
|
||||
unsigned idx) const
|
||||
{
|
||||
uint8_t const *data { (uint8_t *)&header };
|
||||
_report_string(xml, type, _string_set_item(header, data[idx]));
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_bios(Reporter::Xml_generator &xml,
|
||||
Smbios_structure const &header) const
|
||||
{
|
||||
uint8_t const *data { (uint8_t *)&header };
|
||||
xml.attribute("description", "BIOS Information");
|
||||
if (header.length < 18) {
|
||||
_warn("SMBIOS BIOS structure has bad length");
|
||||
return;
|
||||
}
|
||||
_report_string_set_item(xml, header, "vendor", 4);
|
||||
_report_string_set_item(xml, header, "version", 5);
|
||||
_report_string_set_item(xml, header, "release-date", 8);
|
||||
{
|
||||
addr_t const code { *(uint16_t const *)(data + 6) };
|
||||
if (code) {
|
||||
xml.node("address", [&] () {
|
||||
xml.attribute("value", Addr_string(Hex(code << 4))); });
|
||||
|
||||
xml.node("runtime-size", [&] () {
|
||||
xml.attribute("value", (0x10000 - code) << 4); });
|
||||
}
|
||||
}
|
||||
{
|
||||
uint16_t code_2;
|
||||
if (header.length < 26) {
|
||||
code_2 = 16;
|
||||
} else {
|
||||
code_2 = *(uint16_t const *)(data + 24);
|
||||
}
|
||||
_report_bios_rom_size(xml, data[9], code_2);
|
||||
}
|
||||
_report_bios_character_0(xml, *(uint64_t const *)(data + 10));
|
||||
if (header.length < 0x13) {
|
||||
return; }
|
||||
|
||||
_report_bios_character_1(xml, data[0x12]);
|
||||
if (header.length < 0x14) {
|
||||
return; }
|
||||
|
||||
_report_bios_character_2(xml, data[0x13]);
|
||||
if (header.length < 0x18) {
|
||||
return; }
|
||||
|
||||
if (data[20] != 0xff && data[21] != 0xff) {
|
||||
xml.node("bios-revision", [&] () {
|
||||
xml.attribute("value", Version_2_string(data[20], ".", data[21]));
|
||||
});
|
||||
}
|
||||
if (data[22] != 0xff && data[23] != 0xff) {
|
||||
xml.node("firmware-revision", [&] () {
|
||||
xml.attribute("value", Version_2_string(data[22], ".", data[23]));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_system_uuid(Reporter::Xml_generator &xml,
|
||||
uint8_t const *data) const
|
||||
{
|
||||
bool only_zeros { true };
|
||||
bool only_ones { true };
|
||||
for (unsigned off = 0; off < 16 && (only_zeros || only_ones); off++)
|
||||
{
|
||||
if (data[off] != 0x00) {
|
||||
only_zeros = false;
|
||||
}
|
||||
if (data[off] != 0xff) {
|
||||
only_ones = false;
|
||||
}
|
||||
}
|
||||
|
||||
xml.node("uuid", [&] () {
|
||||
if (only_ones) {
|
||||
xml.attribute("value", "[not present]");
|
||||
return;
|
||||
}
|
||||
if (only_zeros) {
|
||||
xml.attribute("value", "[not settable]");
|
||||
return;
|
||||
}
|
||||
if ( _version_major > 2 ||
|
||||
(_version_major == 2 && _version_minor >= 6))
|
||||
{
|
||||
xml.attribute("value", Uuid_string(
|
||||
Uuid_hex(data[3]), Uuid_hex(data[2]),
|
||||
Uuid_hex(data[1]), Uuid_hex(data[0]),
|
||||
"-",
|
||||
Uuid_hex(data[5]), Uuid_hex(data[4]),
|
||||
"-",
|
||||
Uuid_hex(data[7]), Uuid_hex(data[6]),
|
||||
"-",
|
||||
Uuid_hex(data[8]), Uuid_hex(data[9]),
|
||||
"-",
|
||||
Uuid_hex(data[10]), Uuid_hex(data[11]),
|
||||
Uuid_hex(data[12]), Uuid_hex(data[13]),
|
||||
Uuid_hex(data[14]), Uuid_hex(data[15])));
|
||||
|
||||
} else {
|
||||
xml.attribute("value", Uuid_string(
|
||||
Uuid_hex(data[0]), Uuid_hex(data[1]),
|
||||
Uuid_hex(data[2]), Uuid_hex(data[3]),
|
||||
"-",
|
||||
Uuid_hex(data[4]), Uuid_hex(data[5]),
|
||||
"-",
|
||||
Uuid_hex(data[6]), Uuid_hex(data[7]),
|
||||
"-",
|
||||
Uuid_hex(data[8]), Uuid_hex(data[9]),
|
||||
"-",
|
||||
Uuid_hex(data[10]), Uuid_hex(data[11]),
|
||||
Uuid_hex(data[12]), Uuid_hex(data[13]),
|
||||
Uuid_hex(data[14]), Uuid_hex(data[15])));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const char *Table::_base_board_type(uint8_t idx) const
|
||||
{
|
||||
switch (idx) {
|
||||
case 1: return "Unknown";
|
||||
case 2: return "Other";
|
||||
case 3: return "Server Blade";
|
||||
case 4: return "Connectivity Switch";
|
||||
case 5: return "System Management Module";
|
||||
case 6: return "Processor Module";
|
||||
case 7: return "I/O Module";
|
||||
case 8: return "Memory Module";
|
||||
case 9: return "Daughter Board";
|
||||
case 10: return "Motherboard";
|
||||
case 11: return "Processor+Memory Module";
|
||||
case 12: return "Processor+I/O Module";
|
||||
case 13: return "Interconnect Board";
|
||||
default: return "[out of spec]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_base_board_handles(Reporter::Xml_generator &xml,
|
||||
uint8_t count,
|
||||
uint8_t const *data) const
|
||||
{
|
||||
for (uint8_t idx = 0; idx < count; idx++) {
|
||||
xml.node("contained-object-handle", [&] () {
|
||||
uint8_t const *value { data + sizeof(uint16_t) * idx };
|
||||
xml.attribute("value", Addr_string(*(uint16_t const *)value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_base_board(Reporter::Xml_generator &xml,
|
||||
Smbios_structure const &header) const
|
||||
{
|
||||
xml.attribute("name", "Base Board Information");
|
||||
if (header.length < 8) {
|
||||
return; }
|
||||
|
||||
_report_string_set_item(xml, header, "manufacturer", 4);
|
||||
_report_string_set_item(xml, header, "product-name", 5);
|
||||
_report_string_set_item(xml, header, "version", 6);
|
||||
_report_string_set_item(xml, header, "serial-number", 7);
|
||||
if (header.length < 9) {
|
||||
return; }
|
||||
|
||||
_report_string_set_item(xml, header, "asset-tag", 8);
|
||||
if (header.length < 10) {
|
||||
return; }
|
||||
|
||||
uint8_t const *data { (uint8_t *)&header };
|
||||
_report_base_board_features(xml, data[9]);
|
||||
if (header.length < 14) {
|
||||
return; }
|
||||
|
||||
_report_string_set_item(xml, header, "location-in-chassis", 10);
|
||||
|
||||
xml.node("chassis-handle", [&] () {
|
||||
xml.attribute("value", *(uint16_t const *)(data + 11)); });
|
||||
|
||||
_report_string(xml, "type", _base_board_type(data[13]));
|
||||
if (header.length < 15) {
|
||||
return; }
|
||||
|
||||
if (header.length < 15 + data[14] * sizeof(uint16_t)) {
|
||||
return; }
|
||||
|
||||
_report_base_board_handles(xml, data[14], data + 15);
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_system(Reporter::Xml_generator &xml,
|
||||
Smbios_structure const &header) const
|
||||
{
|
||||
uint8_t const *data { (uint8_t *)&header };
|
||||
xml.attribute("description", "System Information");
|
||||
if (header.length < 8) {
|
||||
return; }
|
||||
|
||||
_report_string_set_item(xml, header, "manufacturer", 4);
|
||||
_report_string_set_item(xml, header, "product-name", 5);
|
||||
_report_string_set_item(xml, header, "version", 6);
|
||||
_report_string_set_item(xml, header, "serial-number", 7);
|
||||
if (header.length < 25) {
|
||||
return; }
|
||||
|
||||
_report_system_uuid(xml, data + 8);
|
||||
_report_string(xml, "wake-up-type", _system_wake_up_type(data[24]));
|
||||
if (header.length < 27) {
|
||||
return; }
|
||||
|
||||
_report_string_set_item(xml, header, "sku-number", 25);
|
||||
_report_string_set_item(xml, header, "family", 26);
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_smbios_struct(Reporter::Xml_generator &xml,
|
||||
Smbios_structure const &smbios_struct) const
|
||||
{
|
||||
xml.node("structure", [&] () {
|
||||
|
||||
xml.attribute("type", smbios_struct.type);
|
||||
xml.attribute("length", smbios_struct.length);
|
||||
xml.attribute("handle", smbios_struct.handle);
|
||||
|
||||
switch (smbios_struct.type) {
|
||||
case Smbios_structure::BIOS: _report_bios (xml, smbios_struct); break;
|
||||
case Smbios_structure::SYSTEM: _report_system (xml, smbios_struct); break;
|
||||
case Smbios_structure::BASE_BOARD: _report_base_board(xml, smbios_struct); break;
|
||||
default: _warn("structure type not supported"); break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_smbios_structs(Reporter::Xml_generator &xml,
|
||||
Dmi_entry_point const &ep) const
|
||||
{
|
||||
Smbios_structure *smbios_struct { (Smbios_structure *)(
|
||||
(addr_t)&ep + ep.LENGTH) };
|
||||
|
||||
for (uint16_t idx = 0; idx < ep.nr_of_structs; idx++) {
|
||||
|
||||
if ((addr_t)smbios_struct + sizeof(*smbios_struct) > _end) {
|
||||
_warn("SMBIOS structure header exceeds ROM");
|
||||
break;
|
||||
} else if ((addr_t)smbios_struct + smbios_struct->length > _end) {
|
||||
_warn("SMBIOS structure body exceeds ROM");
|
||||
break;
|
||||
}
|
||||
_report_smbios_struct(xml, *smbios_struct);
|
||||
|
||||
/* seek next SMBIOS structure */
|
||||
bool next_exceeds_rom { false };
|
||||
uint8_t const *next { (uint8_t *)(
|
||||
(addr_t)smbios_struct + smbios_struct->length) };
|
||||
|
||||
while (1) {
|
||||
if ((addr_t)next + 2 * sizeof(*next) > _end) {
|
||||
next_exceeds_rom = true;
|
||||
break;
|
||||
}
|
||||
if (next[0] == 0 && next[1] == 0) {
|
||||
next += 2;
|
||||
break;
|
||||
}
|
||||
next++;
|
||||
}
|
||||
if (next_exceeds_rom) {
|
||||
_warn("SMBIOS structure string-set exceeds ROM");
|
||||
break;
|
||||
}
|
||||
smbios_struct = (Smbios_structure *)next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_smbios_ep(Reporter::Xml_generator &xml,
|
||||
Smbios_entry_point const &smbios_ep) const
|
||||
{
|
||||
/* fix weird versions reported by some systems */
|
||||
uint8_t _version_major = smbios_ep.version_major;
|
||||
uint8_t _version_minor = smbios_ep.version_minor;
|
||||
if ((_version_major == 2 && _version_minor == 31) ||
|
||||
(_version_major == 2 && _version_minor == 33))
|
||||
{
|
||||
_warn("fixed weird SMBIOS version");
|
||||
_version_major = 2;
|
||||
_version_minor = 3;
|
||||
|
||||
} else if (_version_major == 2 && _version_minor == 51) {
|
||||
|
||||
_warn("fixed weird SMBIOS version");
|
||||
_version_major = 2;
|
||||
_version_minor = 6;
|
||||
}
|
||||
xml.node("smbios", [&] () {
|
||||
xml.attribute("version",
|
||||
Version_2_string(_version_major, ".", _version_minor));
|
||||
|
||||
xml.attribute("structures", smbios_ep.nr_of_structs);
|
||||
xml.attribute("structures-size", smbios_ep.struct_table_length);
|
||||
|
||||
_report_smbios_structs(xml, smbios_ep.dmi_ep());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Table::_report_dmi_ep(Reporter::Xml_generator &xml,
|
||||
Dmi_entry_point const &ep) const
|
||||
{
|
||||
/* fix weird versions reported by some systems */
|
||||
uint8_t ver_maj { (uint8_t)(ep.bcd_revision >> 4) };
|
||||
uint8_t ver_min { (uint8_t)(ep.bcd_revision & 0xf) };
|
||||
xml.node("dmi", [&] () {
|
||||
xml.attribute("version",
|
||||
Version_2_string(ver_maj, ".", ver_min));
|
||||
|
||||
xml.attribute("structures", ep.nr_of_structs);
|
||||
xml.attribute("structures-size", ep.struct_table_length);
|
||||
|
||||
_report_smbios_structs(xml, ep);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Table::report(Reporter::Xml_generator &xml) const
|
||||
{
|
||||
|
||||
/* check if entry point is valid and of which type it is */
|
||||
char const *const anchor_string { (char *)_base };
|
||||
if (((addr_t)anchor_string + 5 * sizeof(*anchor_string)) > _end) {
|
||||
_warn("anchor string of entry point exceeds ROM");
|
||||
} else if (String<5>(anchor_string) == "_SM_") {
|
||||
|
||||
/* it's an SMBIOS entry point */
|
||||
Smbios_entry_point const &smbios_ep {
|
||||
*(Smbios_entry_point *)anchor_string };
|
||||
|
||||
/* check if SMBIOS entry point is valid */
|
||||
if ((addr_t)&smbios_ep + sizeof(smbios_ep) > _end) {
|
||||
_warn("SMBIOS entry point exceeds ROM");
|
||||
} else if (!smbios_ep.length_valid()) {
|
||||
_warn("SMBIOS entry point has bad length");
|
||||
} else if (!smbios_ep.checksum_correct()) {
|
||||
_warn("SMBIOS entry point has bad checksum");
|
||||
} else if (String<6>((char const *)&smbios_ep.interm_anchor_string) !=
|
||||
"_DMI_")
|
||||
{
|
||||
_warn("SMBIOS entry point has bad intermediate anchor string");
|
||||
} else if (!smbios_ep.interm_checksum_correct()) {
|
||||
_warn("SMBIOS entry point has bad intermediate checksum");
|
||||
} else {
|
||||
|
||||
/* report information from SMBIOS entry point */
|
||||
_report_smbios_ep(xml, smbios_ep);
|
||||
}
|
||||
} else if (String<6>(anchor_string) == "_SM3_") {
|
||||
_warn("SMBIOS3 entry point found, not supported");
|
||||
|
||||
} else if (String<6>(anchor_string) == "_DMI_") {
|
||||
|
||||
Dmi_entry_point const &ep { *(Dmi_entry_point *)anchor_string };
|
||||
|
||||
if (!ep.checksum_correct()) {
|
||||
warning("DMI entry point has bad checksum");
|
||||
} else {
|
||||
_report_dmi_ep(xml, ep);
|
||||
}
|
||||
} else {
|
||||
_warn("entry point has bad anchor string");
|
||||
}
|
||||
}
|
3
repos/os/src/app/smbios_decoder/target.mk
Normal file
3
repos/os/src/app/smbios_decoder/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = smbios_decoder
|
||||
SRC_CC = main.cc
|
||||
LIBS = base
|
@ -50,6 +50,7 @@ rump_ext2
|
||||
sd_card_bench
|
||||
seoul-auto
|
||||
smartcard
|
||||
smbios_decoder
|
||||
smp
|
||||
solo5
|
||||
sub_rm
|
||||
|
Loading…
Reference in New Issue
Block a user